C ++中的内存泄漏(通过new + delete)

时间:2009-08-30 21:35:57

标签: c++ memory-leaks

为了使应用程序没有内存泄漏,C ++项目中的new数量是否与删除次数相匹配?

10 个答案:

答案 0 :(得分:19)

如果您的意思是源代码中的delete实例数与new的实例数相同,则表示没有。{您可以在多个位置编辑对象new,但所有这些对象delete由同一行代码组成。事实上,这是一个常见的习语。

不同类型的智能指针通常会在用户代码的许多位置使用许多不同的对象new,并在库代码中的单个位置delete

修改

从技术上讲,每个成功的内存分配调用都需要与从原始分配调用中获取返回指针的dellocation调用匹配。

大多数new表达式导致调用operator new,分配内存并在新分配的内存中构造对象。使用delete表达式会破坏对象,并导致调用operator delete,这应该释放已分配的内存。

有一些新的表达式可以在预先分配的内存中构建对象(placement new)。这些不应该与删除表达式匹配,但可能需要以与原始分配相对应的方式释放预分配的内存。

答案 1 :(得分:17)

如果您的意思是“在源代码中”,那么编号

请参阅此代码:

int main()
{
    char* buffer = 0; 


    for( int i = 0; i < 42; ++i )
    {
        buffer = new char[1024];
    }

    delete [] buffer; 

    return 0;
}

1个新的,1个删除,((42 - 1)* 1024)个字节的内存泄露。

如果您的意思是“在运行时新建和删除调用”,那么是。用new获取的每个内存都必须与delete一起发布:

int main()
{
    std::vector<char*> bufferList; // or nullptr or NULL whatever


    for( int i = 0; i < 42; ++i )
    {
        bufferList.push_back( new char[1024] );
    }

    for( int i = 0; i < bufferList.size(); ++i )
    {
        delete [] bufferList[i]; 
    }

    return 0;
}

现在执行时,我们为每个新执行的&lt; =&gt;执行了删除操作。没有泄漏。

答案 2 :(得分:7)

是。必须通过删除来匹配每个新内容。

但是,删除通常对您隐藏 - 例如:

{
  std::auto_ptr p( new Foo );
}

这里有一个新的,但是删除(自动发生) 在块的末尾)隐藏在 std :: auto_ptr实现。

答案 3 :(得分:2)

有一些复杂的工具,比如Rational的Purify来测试C ++程序的内存泄漏。不幸的是,在运行时验证代码本身没有内存泄漏通常是一个非常重要的问题。因此,请保持简单,遵循最佳实践并在运行时尽可能多地进行测试。

答案 4 :(得分:1)

您需要将对new的调用与对delete的调用进行匹配。由于C ++是面向对象的编程语言,因此请考虑使用类来创建(在构造函数中)并删除(在析构函数中)在类中声明或使用的变量。事实上,这将利用Resource Acquisition Is InitializationRAII(简称)成语。如果您不想自己编程,可以随时使用memory中的 STL

一个重要的注意事项:如果您使用new分配变量并且您的代码可以抛出异常,那么如果未捕获该异常并且相应地删除了变量,则可能会泄漏内存。

答案 5 :(得分:1)

您是否询问运行时呼叫计数(例如使用仪表分析器计算)?对new(不包括新的位置)和delete运算符进行完全相同的调用次数既不是无泄漏代码的必要条件,也不是充分条件:

  • 删除NULL是无害的,因此许多无泄漏程序比delete调用new次。
  • delete调用new次数但有时删除NULL的程序有泄漏。一些程序调用{​​{1}}的时间比delete多一些,但有时会删除new
  • NULL更频繁地调用new的程序有泄漏。

要验证没有泄漏,您必须验证从delete返回的每个地址是否都传递给new,而不仅仅是验证呼叫计数是否匹配。即使这样过于简单化,因为地址可以重复用于多次分配。

此外,不泄漏已分配内存的程序可能仍会泄漏其他资源(例如OS文件句柄)。

答案 6 :(得分:0)

不完全是。必须使用delete运算符释放使用new运算符分配的任何对象。可以在不同的分支机构中拥有多个运营商(新的或删除的)。

我个人在编写c ++代码时使用boost的shared_ptr。

答案 7 :(得分:0)

如果您要找到检测内存泄漏的初步方法,计算新的/删除将无济于事。但是,如果您使用MS VC,则可以使用CRT为您执行非常基本但有用的泄漏检测:

_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT);
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

这将导致CRT在卸载CRT之前调用_CrtDumpMemoryLeaks。如果有,它会将它们转储到控制台:

Detected memory leaks!
Dumping objects ->
{342} normal block at 0x05A28FD8, 4 bytes long.
 Data: <    > 00 00 00 00 
Object dump complete.

还有一种技术可以使用块的数量({342})找到确切的泄漏位置,但有时它只是知道是否有任何泄漏。

它不会取代适当的内存泄漏检测工具的需要,但可能会限制它们的需求。

我总是在单元测试中使用这种技术。允许我很早就发现非常愚蠢的内存泄漏。

答案 8 :(得分:-1)

嗯,如果您完全没有news而没有deletes,或者如果您有其他类,例如stl,则可以为您管理内存。

您需要将new的来电次数与delete的来电次数相匹配。

通常情况下会变得更复杂。

答案 9 :(得分:-4)

为了避免内存泄漏,您的应用程序应该释放它不再使用的所有内存,除非它在终止期间分配它。没有事件循环的程序中没有内存泄漏的概念(因为,它们的生命周期从一开始就终止:-))。

但这适合成年人。对你来说,是的,每个新的都应该有一个相应的删除(这意味着,在程序执行期间,而不是在你的源代码中!)产生一个好的代码,不要自己开枪!