内存泄漏探测器工作原理

ami*_*990 51 c c++ memory-leaks

内存检漏仪实际上如何工作?一般的基本概念是什么?可以用C++作为语言来解释这一点.

b4h*_*and 60

泄漏检测器有两种不同的工作方式.您可以在分配期间替换可以跟踪更多信息的实现,malloc并且free不关心性能.这与dmalloc工作方式类似.通常,任何malloc"但不是free"的地址都会泄露.

基本实现实际上非常简单.您只需维护每个分配及其行号的查找表,并在释放条目时删除该条目.然后当程序完成后,您可以列出所有泄漏的内存.困难的部分是确定应该释放分配的时间和地点.当有多个指向同一地址的指针时,这就更难了.

实际上,您可能不仅需要单行号,而且还需要丢失分配的堆栈跟踪.

另一种方法是valgrind如何工作,它实现整个虚拟机以跟踪地址和内存引用以及相关的簿记.valgrind方法更昂贵,但也更有效,因为它还可以告诉您其他类型的内存错误,如越界读取或写入.

Valgrind主要用于检测底层指令,并可以跟踪给定内存地址何时没有更多引用.它可以通过跟踪地址的分配做到这一点,因此它可以告诉你,不只是一块内存丢失了,但究竟何时它被湮灭.

C++使事情对于两种类型的泄漏检测的有点困难,因为它增加了newdelete运营商.技术上new可以是一个完全不同的内存来源malloc.但是,在实践中,许多真正的C++实现仅用于malloc实现new或具有使用选项malloc而不是替代方法.

此外,像C++这样的高级语言倾向于使用替代更高级别的方式来分配内存,如std::vectorstd::list.基本的泄漏检测器将分别报告由更高级别模式进行的许多分配.这比说整个容器丢失要有用得多.

  • C++标准没有指定,但就像我说的,在实践中,大多数现实世界的实现都使用相同的底层资源. (3认同)
  • 我们也不要忘记应用程序也可以直接使用OS API分配内存而不是使用`malloc` /`new`,而且STL容器也支持自定义内存分配器(因此应用程序可以使用它想要的任何内存 - 堆栈内存,内存映射文件等). (3认同)
  • @ amit1990:C++实现可能会使用malloc在大块中分配内存然后实现`new`以在该块中使用某种对象池,这似乎是合理的.这可能是为了减少内存碎片,因为相同类型的对象通常具有相同的大小.对于仅拦截malloc的内存调试器,池变为不透明. (2认同)
  • @amit1990:实际上,`new` 和`malloc` 所做的是两件不同的事情。`malloc` 分配一块字节,而 `new` 分配一块字节来存储某种类型的对象,并通过调用其构造函数来初始化该对象。它们不需要从同一个池中分配,也不需要从不同的池中分配。所以你可以假设两者都不是。为了增加主题,Rationale Purify 还负责检测 `malloc/free`、`new/delete` 和 `new[]/delete[]` 不匹配。他们利用 SO 将内存管理调用重定向到他们自己的库。 (2认同)

Ira*_*ter 19

这是一篇关于CheckPointer工具如何工作的已发表的技术论文.

从根本上说,它跟踪所有值(堆和堆栈)的生命周期,以及它们根据语言定义的类型的大小.这使得CheckPointer不仅可以查找泄漏,还可以查找数组外绑定访问,即使对于堆栈中的数组,valgrind也不会这样做.

特别是,它分析源代码以查找所有指针使用.(这本身就是一项任务).

它跟踪每个指针的指针元数据,包括

  • 对指针所指向的堆分配对象或全局或局部变量或函数的对象元数据的引用
  • 指针当前可以访问的对象的(子)对象的地址范围.这可能小于整个对象的地址范围; 例如,如果您获取结构成员的地址,则检测的源代码将仅允许在使用结果指针时访问该成员.

它还跟踪每个对象的类型和位置,即它是函数,全局,线程局部或局部变量,堆分配的内存还是字符串文字常量:

  • 可以安全访问的对象的地址范围,以及
  • 对于存储在堆分配的对象或变量中的每个指针,对该指针的指针元数据的引用.

所有这些跟踪都是通过将原始程序源转换为执行原始程序所做的程序,并交错各种元数据检查或更新例程来完成的.生成的程序已编译并运行.如果元数据检查在运行时失败,则会提供回溯,其中包含失败类型的报告(无效指针,有效边界外的指针,......)

  • 链接站点的存在时间超过StackOverflow超过10年; 它不太可能消失.这个链接可以提供真实的*信息丰富的答案.Web和超链接的目的是避免将整个Web复制到Stackoverflow中.获得一些观点,人们. (12认同)
  • 我认为linke会得到一个很好的答案.但重点是:没有链接它没有用.关于它的规则很清楚.(不需要透视).那么是什么阻止您在depp详细信息中更多地总结链接中包含的信息? (10认同)
  • Downvoted,因为答案是,如果链接应该关闭,不是真正的信息. (4认同)
  • @Zaibis没有链接,你仍然可以知道Google"Ira Baxter CheckPointer"或"Semantic Designs CheckPointer" (2认同)

Tho*_*ler 8

这是标记的C和C++,没有提到操作系统.这个答案适用于Windows.

C

Windows具有虚拟内存的概念.进程可以获得的任何内存都是虚拟内存.这是通过VirtualAlloc()[MSDN]完成的.您可以想象泄漏检测器在该函数上设置断点,并且无论何时调用它,它都会获取callstack并将其保存在某处.然后它可以为VirtualFree()[MSDN]做类似的事情.

然后可以识别差异并将其与已保存的callstack一起显示.

C++

C++有一个不同的概念:它从VirtualAlloc()获取大的64kb块并将其拆分成更小的块,称为Heap.C++堆管理器来自Microsoft,提供新方法HeapAlloc()[MSDN]HeapFree()[MSDN].

然后,您可以像以前一样做,但实际上,该功能已经内置.Microsoft的GFlags [MSDN]工具可以启用跟踪:

屏幕截图:为记事本启用了GFlags

在这种情况下,它将为C++堆管理器调用保存多达50 MB的callstack信息.

由于也可以通过Windows注册表启用该设置,因此内存泄漏检测器可以轻松使用它.

一般概念

正如您所看到的,一般概念是跟踪分配和解除分配,比较它们并显示差异的callstack.

  • 1.您不需要在C中使用VirtualAlloc.大多数程序仍然使用`malloc`和`free`(实际上,直接使用VirtualAlloc很少).2. C++内存管理器是一回事.3. HeapAlloc等人.不是C++特定的,但可以在C中使用(可能是如何实现`malloc`). (3认同)