std::string 运算符+() 内存泄漏?
我很担心,因为我写了一个小应用程序,如果我相信 valgrind (我实际上做了什么),似乎存在内存泄漏:
==9321== 251 bytes in 7 blocks are definitely lost in loss record 1 of 1
==9321== at 0x402569A: operator new(unsigned int) (vg_replace_malloc.c:255)
==9321== by 0x40D3D05: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x40D4977: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x40D57AC: std::string::reserve(unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x40D5EE6: std::string::operator+=(char) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x804E113: xl2::TextParser::getNextLfLine() (TextParser.cpp:162)
==9321== by 0x804BFD5: xl2::UsbTree::parseStringInfo(xl2::TextParser&, std::string&, std::string&) (UsbTree.cpp:362)
==9321== by 0x804B881: xl2::UsbTree::parseDevicesFile(std::string) (UsbTree.cpp:204)
==9321== by 0x804B34E: xl2::UsbTree::updateTree() (UsbTree.cpp:70)
==9321== by 0x804E2E4: scan(std::string) (testUsbTree.cpp:75)
==9321== by 0x804E6CC: executeCommand(std::string) (testUsbTree.cpp:132)
==9321== by 0x804E8F6: hushLoop() (testUsbTree.cpp:153)
这是有问题的函数:
/**
* Returns the next line separated by UNIX style LF
* @return The next line separated by UNIX style LF
*/
std::string TextParser::getNextLfLine()
{
std::string line; // The builded line
while(this->hasMoreToken())
{
line += this->m_pText[this->m_iTokenLocation++];
// Check if we have just seen a CR/LF character
if(this->m_pText[this->m_iTokenLocation - 1] == '\n')
return line;
}
return line;
}
程序通过离开主函数正确终止(不调用退出())。
我只是不明白为什么会出现内存泄漏。因为我的字符串是在堆栈中复制的,并且当函数离开时原始字符串应该被清除,对吗?或者误差可能会更高?在顶层,我还将返回的值分配给一个局部变量,然后将其作为字段放入对象中(通过复制)...
所以我想知道泄漏是否来自标准库或 valgrind,这将是真正令人惊讶的!
强烈赞赏任何指向未泄漏内存的指针:-p!
I'm quite worry because I wrote a little application and it seems that there is a memory leak if I believe valgrind (What I actually do):
==9321== 251 bytes in 7 blocks are definitely lost in loss record 1 of 1
==9321== at 0x402569A: operator new(unsigned int) (vg_replace_malloc.c:255)
==9321== by 0x40D3D05: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x40D4977: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x40D57AC: std::string::reserve(unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x40D5EE6: std::string::operator+=(char) (in /usr/lib/libstdc++.so.6.0.13)
==9321== by 0x804E113: xl2::TextParser::getNextLfLine() (TextParser.cpp:162)
==9321== by 0x804BFD5: xl2::UsbTree::parseStringInfo(xl2::TextParser&, std::string&, std::string&) (UsbTree.cpp:362)
==9321== by 0x804B881: xl2::UsbTree::parseDevicesFile(std::string) (UsbTree.cpp:204)
==9321== by 0x804B34E: xl2::UsbTree::updateTree() (UsbTree.cpp:70)
==9321== by 0x804E2E4: scan(std::string) (testUsbTree.cpp:75)
==9321== by 0x804E6CC: executeCommand(std::string) (testUsbTree.cpp:132)
==9321== by 0x804E8F6: hushLoop() (testUsbTree.cpp:153)
Here is the function in question :
/**
* Returns the next line separated by UNIX style LF
* @return The next line separated by UNIX style LF
*/
std::string TextParser::getNextLfLine()
{
std::string line; // The builded line
while(this->hasMoreToken())
{
line += this->m_pText[this->m_iTokenLocation++];
// Check if we have just seen a CR/LF character
if(this->m_pText[this->m_iTokenLocation - 1] == '\n')
return line;
}
return line;
}
The programm terminates correctly by leaving the main funciton (no call to exit()).
I just don't understand why there is a memory leak. As my string is copied in the stack and the original string is supposed to be cleaned when the function is left, right? Or the error could be higher? At top level I also assign the returned value to a local variable that is then put as field into an object (by copy) ...
So I was wondering if the leak comes from the standard library or valgrind what would be really surprising!
Any pointers to not leaked memory is strongly appreciated :-p!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
引用Valgrind 常见问题解答
也在 GCC 常见问题解答中进行了讨论
To quote Valgrind FAQ
Also discussed in GCC FAQ
我不会太担心 STL 泄漏。
默认的 STL 分配器(用于 gcc)使用巧妙的技巧来最大限度地提高效率,Valgrind 经常将其报告为泄漏。值得注意的是,它会池化内存,这意味着当您清除
字符串
时,它会保留内存,并且可以在下次插入map
或向量
时重用它> 例如。我不认为池本身在程序结束时被正确处置,可能是为了避免静态销毁顺序惨败(即,想象池被处置,然后您请求内存,urk)。因此,它会在程序结束并且操作系统强制收回内存之前泄漏。
I would not worry too much about STL leaks.
The default STL allocator (for gcc) uses clever tricks to maximize efficiency that Valgrind often reports as leaks. Notably it pools memory, meaning that it keeps memory around when you clear a
string
and may reuse it next time you insert in amap
or avector
for example.I don't think the pool itself is properly disposed of at the end of the program, probably to avoid the Static Destruction Order Fiasco (ie, imagine that the pool is disposed of and you then request memory, urk). Thus it leaks... right before your program ends and the OS gets the memory back forcefully.
我怀疑编译器正在使用 NRVO 将临时字符串放入其真正的返回位置。然后,该返回字符串存储在已分配并从堆中泄漏的对象内。
I suspect what's happening is the compiler is using NRVO to put your temporary string into its real return location. That return string is then stored inside an object that's allocated and leaked off the heap.