How do you detect/avoid Memory leaks in your (Unmanaged) code?在非托管C / C ++代码中,检测内存泄漏的最佳实践是什么? 和编码指南要避免? (好像就是这么简单;) 过去,我们使用了一些愚蠢的方法:每个内存分配调用都有一个计数器递增,释放时递减。 在程序结束时,计数器值应为零。 我知道这不是一个好方法,而且有一些问题。 (例如,如果您要释放由平台API调用分配的内存,则您的分配计数将与您的释放计数不完全匹配。当然,然后,在调用分配了内存的API调用时,我们会增加计数器。) 我期待您的经验,建议,以及一些简化此工具的参考。 如果您的C / C ++代码可移植到* nix,则没有什么比Valgrind好。 如果您使用的是Visual Studio,Microsoft提供了一些有用的功能来检测和调试内存泄漏。
我将从本文开始: 这是这些文章的快速摘要。首先,包括以下标头:
然后,您需要在程序退出时调用此命令:
另外,如果您的程序并非每次都在同一位置退出,则可以在程序开始时调用它:
现在,当程序退出时,所有未释放的分配将连同在其中分配的文件以及分配发生一起打印在"输出"窗口中。 此策略适用于大多数程序。但是,在某些情况下变得困难或不可能。使用在启动时进行一些初始化的第三方库可能会导致其他对象出现在内存转储中,并使跟踪泄漏变得困难。同样,如果您的任何类的成员与任何内存分配例程(例如malloc)具有相同的名称,则CRT调试宏将引起问题。 上面引用的MSDN链接中还介绍了其他可以使用的技术。
在C ++中:使用RAII。 作为C ++开发人员,这里有一些简单的准则: 至于个人检测内存泄漏,我一直使用Visual Leak Detector,发现它非常有用。 我使用DevStudio已经有很多年了,它让我感到惊讶的是,有多少程序员不了解调试运行时库中提供的内存分析工具。以下是一些入门链接: 跟踪堆分配请求-特别是有关唯一分配请求号的部分
当然,如果您不使用DevStudio,那么它将不会特别有用。
我很惊讶没有人提到Windows OS的DebugDiag。 Visual Leak Detector是一个非常好的工具,尽管它不支持VC9运行时上的调用(例如MSVCR90D.DLL)。 调试模式下的Microsoft VC ++会显示内存泄漏,尽管它不会显示泄漏的位置。
如果您使用的是C ++,则始终可以避免显式地使用new:您有 当不可避免要使用new时,请尝试将其隐藏在构造函数中(并在delete构造函数中隐藏delete);同样适用于第三方API。 那里有各种各样的替换" malloc"库,这些库可让您最后调用一个函数,它将告诉您所有未释放的内存,并且在许多情况下,它们是谁首先分配(或新分配)了它。
如果您使用的是MS VC ++,我可以从代码项目中强烈推荐此免费工具: 您只需将类添加到您的项目中,然后调用
您想要检查泄漏的代码之前和之后。 构建并运行代码后,Jochen将提供一个简洁的GUI工具,您可以在其中加载生成的.xmlleaks文件,并浏览生成每个泄漏的调用堆栈,以查找有害的代码行。 Rational的(现在由IBM拥有)PurifyPlus以类似的方式说明了泄漏,但是我发现泄漏查找器工具实际上更易于使用,而且它的好处是不需要花费数千美元! 如果您使用的是Visual Studio,则可能值得研究Bounds Checker。它不是免费的,但是在发现我的代码中的泄漏方面非常有用。它不仅会导致内存泄漏,还会导致GDI资源泄漏,WinAPI使用错误以及其他问题。它甚至可以向您显示泄漏内存的初始化位置,从而更容易追踪泄漏。 我自己从未使用过它,但是我的C朋友告诉我Purify。
我想提供一些我过去使用过的东西:一个基本的泄漏检查器,它是源代码级别的,并且是相当自动的。 您可能会发现它很有用。 尽管有点残酷,但我不让我感到尴尬。 即使它与某些win32挂钩相关联,也应易于缓解。
使用它时,必须注意以下几点:不要做任何需要依靠基础代码中的 该设计旨在允许您打开和关闭检查器,而无需重新编译包括其标头的所有内容。在要跟踪检查并重新生成一次的位置包括泄漏检查.h。之后,编译带有或不带有LEAKCHECK#define'd的leakcheck.cpp,然后重新链接以将其打开和关闭。包含unleakcheck.h将在文件中本地将其关闭。提供了两个宏:CLEARALLOCINFO()将避免在遍历分配不包含泄漏检查.h的代码时报告相同的文件和行。 ALLOCFENCE()只是在生成的报告中删除一行,而不进行任何分配。 再次提醒您,我已经有一段时间没有使用它了,您可能需要使用它。我将其放入以说明该想法。如果真的有足够的兴趣,我将愿意举一个示例,在此过程中更新代码,并用更好的名称替换下面URL的内容,其中包括一个语法清晰的清单。 您可以在这里找到它:http://www.cse.ucsd.edu/~tkammeye/leakcheck.html 您是通过插值自己的syscall函数(记录调用,然后将调用传递给实函数)来计数分配和释放吗? 这是跟踪来自未编写代码的调用的唯一方法。 查看ld.so的手册页。或在某些系统上为ld.so.1。 也可以使用Google LD_PRELOAD,您会在www.itworld.com上找到一些有趣的文章来解释该技术。 我认为这个问题没有简单的答案。您如何真正采用该解决方案取决于您的要求。您是否需要跨平台解决方案?您使用的是new / delete还是malloc / free(或两者都使用)?您是否真的只是在寻找"泄漏",还是想要更好的保护,例如检测缓冲区溢出(或溢出)? 如果您在Windows端工作,则MS调试运行时库具有一些基本的调试检测功能,并且正如另一个已经指出的那样,您的源代码中可以包含几个包装程序,以帮助进行泄漏检测。寻找一个可以同时使用new / delete和malloc / free的软件包,显然可以为您提供更大的灵活性。 我对Unix方面的了解不足以提供帮助,尽管其他人也提供了帮助。 但是,不仅仅是泄漏检测,还有通过缓冲区溢出(或溢出)来检测内存损坏的概念。我认为,这种调试功能比普通的泄漏检测更加困难。如果您使用的是C ++对象,则这种类型的系统也会更加复杂,因为可以以多种方式删除多态类,从而在确定要删除的真正基址指针时会遇到麻烦。我知道没有一个好的"免费"系统可以对超限提供良好的保护。我们已经编写了一个系统(跨平台),发现它具有很大的挑战性。
对于Linux: Goolge Perftools的优点是有很多工具可以进行类似的分配/免费计数:
防止泄漏的最佳方法是最小化malloc使用的程序结构。从编程的角度来看,这不仅是件好事,而且还可以提高性能和可维护性。我不是在谈论使用其他东西来代替malloc,而是在重用对象并在传递的所有对象上保留非常明确的标签,而不是像那些经常在带有垃圾收集器的语言中习惯的那样分配随意的对象像Java。 例如,我正在处理的程序具有一堆代表图像数据的框架对象。每个框架对象都有子数据,框架的析构函数将释放这些子数据。该程序保留所有已分配帧的列表,并且在需要新帧时,检查未使用帧对象的列表,以查看它是否可以重用现有帧而不是分配新帧。关闭时,它仅遍历列表,释放所有内容。
我建议从软件验证中使用Memory Validator。 一个非常完整和快速的工具。 Paul Nettle的mmgr是我长期以来最喜欢的工具。您在源文件中包含mmgr.h,定义TEST_MEMORY,它提供了一个文本文件,其中充满了应用程序运行期间发生的内存问题。
至少对于MS VC ++,C运行时库具有一些我发现过去有用的功能。检查MSDN帮助中的 通用编码指南:
在Motorola手机操作系统上,我们劫持了内存分配库以观察所有内存分配。它有助于发现内存分配的许多问题。 内存调试工具值得一试,但是多年来,我发现可以使用两个简单的方法来防止大多数内存/资源泄漏被编码。 在为要分配的资源编写获取代码之后,立即编写发布代码。使用这种方法,更难以"忘记",并且在某种意义上迫使人们认真考虑资源的生命周期,这些资源的生命周期是预先使用而不是暂时使用。 尽量少使用return。如果可能,分配的内容只能在一个地方释放。资源获取与释放之间的条件路径应设计得尽可能简单明了。 在此列表的顶部(当我阅读时)是valgrind。如果您能够在测试系统上重现泄漏,则Valgrind非常有用。我已经成功地使用了它。 如果您刚刚发现生产系统正在泄漏并且不知道如何在测试中重现该怎么办?在生产系统的状态下会捕获一些错误的证据,这可能足以提供问题的根源,以便您可以重现它。
这就是蒙特卡洛采样的地方。阅读Raymond Chen的博客文章, http://github.com/tialaramex/leakdice/tree/master 大多数内存探查器都会将我的大型复杂Windows应用程序减慢到导致结果无用的地步。有一种工具可以很好地发现我的应用程序中的泄漏:UMDH-http://msdn.microsoft.com/zh-cn/library/ff560206%28VS.85%29.aspx Valgrind是Linux的不错选择。在MacOS X下,您可以启用MallocDebug库,该库具有用于调试内存分配问题的多个选项(请参阅malloc联机帮助页,"环境"部分包含相关详细信息)。 OS X SDK还包括一个称为MallocDebug的工具(通常安装在/ Developer / Applications / Performance Tools /中),该工具可以帮助您监视使用情况和泄漏。 rmdebug是一个不错的malloc,calloc和reallloc替代品,使用起来非常简单。与valgrind相比,它要快得多,因此可以广泛地测试代码。当然,它有一些缺点,一旦发现泄漏,您可能仍需要使用valgrind来查找泄漏的位置,并且只能测试直接执行的malloc。如果某个库因使用不正确而泄漏,则rmdebug找不到。 http://www.hexco.de/rmdebug/ 检测: 调试CRT 避免: Boehm GC智能指针 Mtrace似乎是Linux的标准内置工具。这些步骤是: MALLOC_TRACE = / tmp / mtrace.dat 导出MALLOC_TRACE; (我必须先使用yum install glibc_utils在我的fedora系统上安装mtrace perl脚本) |