内存泄漏调试

10

如果没有追踪工具,有哪些技术可以用来检测/调试内存泄漏?


需要一点帮助 - 是什么语言、平台、品牌? - n8wrl
你使用的是哪个平台?Windows/Linux?你使用的是什么编程语言? - Matt Wrock
哪个嵌入式平台? - twk
哪个内核和C库是魔法问题。对于不同的人,“平台”意味着不同的事情。 - Tim Post
6个回答

9
拦截所有分配和释放内存的函数(根据平台,列表可能看起来像:malloc、calloc、realloc、strdup、getcwd、free),除了执行这些函数最初的操作之外,在某个地方保存调用信息,通常是在动态增长的全局数组中,对于多线程程序,需要使用同步原语进行保护。
这些信息可能包括函数名称、请求的内存量、成功分配块的地址、堆栈跟踪,让您能够确定调用者是谁等等。在 free() 中,从数组中删除相应的元素(如果没有,则传递给 free 的指针是错误的,早期检测到这个错误也是好的)。当程序结束时,转储数组的剩余元素-它们将是泄漏的块。不要忘记全局对象在 main() 之前和之后分配和释放资源。为了正确计算这些资源,您需要在最后一个全局对象被销毁后转储剩余资源,因此可能需要对编译器运行时进行小的修改。

在使用标准libc的生产设备上(必须从操作系统供应商更新)...这有什么用处?我很欣赏你的想法,但你提出的解决方案并不实际。此外,malloc()和free()在不同平台上非常挑剔。我没有对此进行投票,但我不能支持一些不可靠和不可移植的东西。 - Tim Post
在使用标准libc的生产设备上,您可以使用以下方法拦截内存分配函数:http://www.gnu.org/software/libtool/manual/libc/Hooks-for-Malloc.html。顺便说一下,这个问题已经在SO上讨论过了:https://dev59.com/2UXRa4cB1Zd3GeqPt7WM - dmityugov

6
  1. 检查你的循环
  2. 查看你分配变量的位置 - 你是否曾经释放它们?
  3. 尝试使用怀疑代码的小子集来重现泄漏。
  4. 制作跟踪工具 - 你总是可以记录到文件中。

绝对要检查循环。几乎所有与泄漏有关的内容都必须在经常循环的代码中。大量程序在只执行一次的代码中存在泄漏,但没有人注意或关心。 - Kevin Gale
一个内存泄漏可能就像是 if (i ==1); str=strdup("foo"); 不仅仅是循环,条件语句也会产生影响。如果没有像valgrind这样的工具,最好的方法就是让更多的人关注代码的演变。你不能指望编译器能够警告你所有可能出现的问题 :) - Tim Post

5

一种可能的方法是编译代码并在可以利用内置工具的系统上执行它(例如在Solaris上使用libumem,或在Linux上使用libc capability)。


1
+1,mcheck()和mprobe()是我在无法安装valgrind的设备上的好朋友 :) - Tim Post

4
分而治之是最好的方法。如果您已经以系统化的方式编写了代码,那么调用代码的子集应该非常容易。最好的方法是反复执行每个代码段,并观察您的内存使用情况是否稳定上升,如果没有,请继续进行下一个代码段。
此外,关于内存泄漏的维基百科文章在参考文献部分提供了几个针对不同系统(Windows、macOS、Linux等)检测内存泄漏的重要链接。

2

类似的问题在SO上:

除了其他人提到的手动检查技术外,您还应考虑使用代码分析工具,例如valgrind

以下是他们网站上的介绍:

Valgrind是一个屡获殊荣的仪器化框架,用于构建动态分析工具。有一些Valgrind工具可以自动检测许多内存管理和线程错误,并详细记录您的程序的性能。您还可以使用Valgrind构建新工具。

Valgrind发行版目前包括六个生产质量工具:一个内存错误检测器、两个线程错误检测器、一个缓存和分支预测分析器、一个调用图生成缓存分析器和一个堆分析器。它还包括两个实验性工具:一个堆/栈/全局数组溢出检测器和一个SimPoint基本块向量生成器。它可以运行在以下平台上:X86/Linux、AMD64/Linux、PPC32/Linux、PPC64/Linux和X86/Darwin(Mac OS X)。


我认为OP试图表达的是他不能使用像Valgrind这样的动态分析工具,当他说“没有跟踪工具”时。我不知道Valgrind可以在哪些嵌入式平台上运行。他可以尝试使用Splint(http://splint.org/),它是一种静态分析工具。 - Falaina

0

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