简体   繁体   English

使用C ++字符串可能发生内存泄漏

[英]Possible memory leak using C++ string

Consider the following C++ program: 考虑以下C ++程序:

#include <cstdlib> // for exit(3)
#include <string>
#include <iostream>
using namespace std;

void die()
{
    exit(0);
}

int main()
{
    string s("Hello, World!");
    cout << s << endl;
    die();
}

Running this through valgrind shows this (some output trimmed for brevity): 通过valgrind运行这个显示了这个(一些输出为了简洁而修剪):

==1643== HEAP SUMMARY:
==1643==     in use at exit: 26 bytes in 1 blocks
==1643==   total heap usage: 1 allocs, 0 frees, 26 bytes allocated
==1643==
==1643== LEAK SUMMARY:
==1643==    definitely lost: 0 bytes in 0 blocks
==1643==    indirectly lost: 0 bytes in 0 blocks
==1643==      possibly lost: 26 bytes in 1 blocks
==1643==    still reachable: 0 bytes in 0 blocks
==1643==         suppressed: 0 bytes in 0 blocks

As you can see, there's a possibility that 26 bytes allocated on the heap were lost. 如您所见,堆上分配的26个字节可能会丢失。 I know that the std::string class has a 12-byte struct (at least on my 32-bit x86 arch and GNU compiler 4.2.4), and "Hello, World!" 我知道std::string类有一个12字节的结构(至少在我的32位x86 arch和GNU编译器4.2.4上)和“Hello,World!” with a null terminator has 14 bytes. 使用null终止符有14个字节。 If I understand it correctly, the 12-byte structure contains a pointer to the character string, the allocated size, and the reference count (someone correct me if I'm wrong here). 如果我理解正确,12字节结构包含指向字符串的指针,分配的大小和引用计数(如果我在这里错了,有人会纠正我)。

Now my questions: How are C++ strings stored with regard to the stack/heap? 现在我的问题是:如何在堆栈/堆中存储C ++字符串? Does a stack object exist for a std::string (or other STL containers) when declared? 声明时是否存在std::string (或其他STL容器)的堆栈对象?

PS I've read somewhere that valgrind may report a false positive of a memory leak in some C++ programs that use STL containers (and "almost-containers" such as std::string ). PS我在某处读过valgrind 可能会报告某些使用STL容器的C ++程序(以及“几乎容器”如std::string )的内存泄漏误报。 I'm not too worried about this leak, but it does pique my curiosity regarding STL containers and memory management. 我并不太担心这种泄漏,但它确实激起了我对STL容器和内存管理的好奇心。

Calling exit "terminates the program without leaving the current block and hence without destroying any objects with automatic storage duration". 调用exit “终止程序而不离开当前块,因此不会破坏任何具有自动存储持续时间的对象”。

In other words, leak or not, you shouldn't really care. 换句话说,泄漏与否,你应该不在乎。 When you call exit , you're saying "close this program, I no longer care about anything in it." 当你打电话给exit ,你说“关闭这个程序,我不再关心其中的任何内容。” So stop caring. 所以停止关怀。 :) :)

Obviously it's going to leak resources because you never let the destructor of the string run, absolutely regardless of how it manages those resources. 显然它会泄漏资源,因为你永远不会让字符串的析构函数运行,绝对不管它如何管理这些资源。

Others are correct, you are leaking because you are calling exit. 其他人是正确的,你正在泄漏,因为你正在呼叫退出。 To be clear, the leak isn't the string allocated on the stack, it is memory allocated on the heap by the string. 要清楚,泄漏不是堆栈上分配的字符串,而是字符串在堆上分配的内存。 For example: 例如:

struct Foo { };

int main()
{
    Foo f;
    die();
}

will not cause valgrind to report a leak. 不会导致valgrind报告泄漏。

The leak is probable (instead of definite) because you have an interior pointer to memory allocated on the heap. 泄漏是可能的(而不是确定的)因为你有一个指向堆上分配的内存的内部指针。 basic_string is responsible for this. basic_string负责这一点。 From the header on my machine: 从我的机器上的标题:

   *  A string looks like this:
   *
   *  @code
   *                                        [_Rep]
   *                                        _M_length
   *   [basic_string<char_type>]            _M_capacity
   *   _M_dataplus                          _M_refcount
   *   _M_p ---------------->               unnamed array of char_type
   *  @endcode
   *
   *  Where the _M_p points to the first character in the string, and
   *  you cast it to a pointer-to-_Rep and subtract 1 to get a
   *  pointer to the header.

They key is that _M_p doesn't point to the start of the memory allocated on the heap, it points to the first character in the string. 它们的关键是_M_p不指向堆上分配的内存的开始,它指向字符串中的第一个字符。 Here is a simple example: 这是一个简单的例子:

struct Foo
{
    Foo()
    {
        // Allocate 4 ints.
        m_data = new int[4];
        // Move the pointer.
        ++m_data;
        // Null the pointer
        //m_data = 0;
    }
    ~Foo()
    {
        // Put the pointer back, then delete it.
        --m_data;
        delete [] m_data;
    }
    int* m_data;
};

int main()
{
    Foo f;
    die();
}

This will report a probable leak in valgrind. 这将报告valgrind可能发生的泄漏。 If you comment out the lines where I move m_data valgrind will report 'still reachable'. 如果你注释掉我移动的行m_data,valgrind将报告'仍然可以访问'。 If you uncomment the line where I set m_data to 0 you'll get a definite leak. 如果取消注释我将m_data设置为0的行,您将获得明确的泄漏。

The valgrind documentation has more information on probable leaks and interior pointers. valgrind 文档提供了有关可能泄漏和内部指针的更多信息。

Of course this "leaks", by exit ing before s 's stack frame is left you don't give s 's destructor a chance to execute. 当然这是“泄漏”,通过在s的堆栈框架之前exit ,你不会给s的析构函数执行一次机会。

As for your question wrt std::string storage: Different implementations do different things. 关于你的问题wrt std::string storage:不同的实现做不同的事情。 Some allocate some 12 bytes on the stack which is used if the string is 12 bytes or shorter. 有些在堆栈上分配了大约12个字节,如果字符串是12个字节或更短,则使用该字节。 Longer strings go to the heap. 更长的字符串进入堆。 Other implementations always go to the heap. 其他实现总是进入堆。 Some are reference counted and with copy-on-write semantics, some not. 有些是引用计数和写时复制语义,有些则不是。 Please turn to Scott Meyers' Effective STL , Item 15. 请转向Scott Meyers的Effective STL ,第15项。

gcc STL has private memory pool for containers and strings. gcc STL具有容器和字符串的私有内存池。 You can turn this off ; 你可以关掉它; look in valgrind FAQ 看看valgrind FAQ

http://valgrind.org/docs/manual/faq.html#faq.reports http://valgrind.org/docs/manual/faq.html#faq.reports

I would avoid using exit() I see no real reason to use that call. 我会避免使用exit()我认为没有真正的理由使用该调用。 Not sure if it will cause the process to stop instantly without cleaning up the memory first although valgrind does still appear to run. 虽然valgrind似乎仍在运行,但不确定是否会在不清理内存的情况下立即停止进程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM