避免C/C++中的内存泄漏的方法

11

有哪些提示可以帮助我避免应用程序中的内存泄漏?在我的当前项目中,我使用一种名为"INSURE++"的工具来查找内存泄漏并生成报告。

除了使用这种工具外,还有哪些方法可以识别内存泄漏并解决它?


10
你使用的是C还是C++?对于这两种语言,可用的解决方案是非常不同的。 - Greg Hewgill
我正在使用C语言。您能否提供C和C++的解决方案? - Ankur
7
@Ankur:一个对于C语言有意义的答案在C++中可能没有意义,反之亦然。内存管理是在C++中发生变化的一部分。 - Billy ONeal
1
@Ankur:在C语言中值得使用的解决方案,在C++中也不会值得使用,因为C++提供了极其不同的解决方案。 - Puppy
6个回答

11

有三种主要方法可以做到这一点。

第一种方法是从一开始就不要创建内存泄漏。在这里防御性编程技术非常有价值。参见这篇优秀的演示文稿以概述此问题,或者参见Secure C编码中的相关章节。我更熟悉C而不是C++,但我了解到C++的智能指针在这方面很有用。

第二种方法是进行静态分析,试图检测源代码中的错误。最初属于此类别的工具是lint,但现在已经过时了。据我所知,最好的工具是商业工具,如Coverity。然而,一些免费的工具存在

第三种方法是在运行时检测内存泄漏,就像INSURE++所做的那样。这里推荐Valgrind,它非常出色。它可能会帮助您捕获您已经引入的错误。如果您有一个覆盖率良好的测试套件,它尤其有帮助。


7

对于C语言,良好的代码组织非常重要。例如,不要将对malloc()和free()的调用散落在整个代码库中。将它们集中到两个函数中,这样你就只有一个检查点。最简单的方法是计算成功调用的次数,并在程序退出时检查它们是否平衡。

static unsigned long mymem_count_alloc = 0;
static unsigned long mymem_count_free  = 0;

void *mymem_alloc (size_t size)
{
    void *p;

    p = malloc(size);
    if (p)
    {
        mymem_count_alloc++;
    }
    else
        error logging/handling/signaling

    return (p);
}

void mymem_free (void *p)
{
    if (p)
    {
        free(p);
        mymem_count_free++;
    }
}

void mymem_check (void)
{
    if (mymem_count_alloc != mymem_count_free)
        error alert
}

您可以对不同的数据结构采用相同的方法。在需要为字符串分配内存时,请使用mystr_alloc和mystr_free。当检测到泄漏时,您可以快速缩小范围。

+1 主要是针对"For C, a good code organization helps..."。个人而言,我更倾向于不使用这种方法。我会使用不透明的数据结构来强制使用函数来创建/销毁每个特定的数据类型。计数会转移到这些数据结构的创建/销毁函数中。你确实需要清晰地组织你的代码,因为很容易混乱。这足以捕捉到许多泄漏,而valgrind非常擅长捕捉数组中的栅栏错误。 - James Morris
话虽如此,这种方法仍然很有用,但我肯定希望它的使用是有条件的:它替换了调试版本中的malloc/free,但在发布版本中仍然使用malloc/free。 - James Morris
@James:我也采用创建/销毁方法。但是在其中,类似于malloc/free的包装函数总是被使用,当然比这个示例更为复杂。错误处理部分总是必要的,如果在调用库函数时某些内容总是必要的话,那么它应该成为函数本身的一部分,或者如果无法操作函数,则应将其放入包装器中,关于DRY原则。https://dev59.com/uknSa4cB1Zd3GeqPQK4P#1530581 - Secure
将其有条件地编译的基本思想是从发布版本中删除我认为是调试代码的内容。 - James Morris
如果您的mymem_alloc函数执行错误检查,那么传递错误字符串吗?调用者是否仍然需要在继续之前检查mymem_alloc的返回值?您如何处理这种情况?有没有在线上可以查看的示例代码?(这些模板式的内容正是我目前遇到的大部分问题...) - James Morris
显示剩余2条评论

2
我们是在讨论寻找泄漏的工具,还是编写代码以避免泄漏?
对于前者,可以使用上述提到的valgrind,或者如果您拥有IBM许可证,则可以使用IBM工具的Rational套件。Dr. Dobbs推荐了CompuWare的BoundsChecker,但那是在2002年。
对于后者,请参见:
C++惯用语法以避免内存泄漏?

http://www.cprogramming.com/tutorial/memory_debugging_parallel_inspector.html

http://scottmcpeak.com/memory-errors/

http://www.yolinux.com/TUTORIALS/C++MemoryCorruptionAndMemoryLeaks.html


我只是想添加一篇关于避免这个问题的最佳实践的好文章: https://mousomer.wordpress.com/2010/11/03/simple-rules-to-avoid-memory-leaks-in-c/ - Ken

2
智能指针在自动化对象生命周期方面非常有帮助:

http://ootips.org/yonat/4dev/smart-pointers.html

在可能的情况下,应该在相关作用域内使用栈分配的对象,而不是使用new/delete。
像valgrind这样的工具会有一些开销,并且可能会减慢运行速度。如果您了解代码库以及容易出现的泄漏类型,可以针对特定类实现轻量级检查(甚至只是一个简单的对象计数器,在退出时将其与零进行比较)。当这些轻量级检查被触发时,它们可以激励您进行更广泛的valgrind调试会话。

1

使用智能指针,例如 std::shared_ptr<t> (C++0x),std::tr1::shared_ptr<t> (TR1),或者 boost::shared_ptr<t>。当然,这个解决方案只适用于 C++ -- 在 C 中你需要自己解决。


0
避免还是检测?首先要检测并尝试理解何时何地以及为什么会出现问题...另一种方法可能是使用GC库,例如此处描述的库,但也可能存在其他(更好的)库。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接