Windows 下内存泄漏检测工具 VLD
VLD 的使用
通常在 main 函数所在的 cpp 文件中 include <vld.h>
即可,运行程序,退出后产生检测报告
注意事项
-
如果有
include "stdafx.h"
,则include <vld.h>
放在其后,否则放在最前面 -
VLD 仅在
debug
版本有效 -
如果想将产生的日志文件保存在文件中,需要将
vld.ini
(VLD 安装目录下)复制到可执行文件目录下,然后做如下修改 -
ReportFile =.\memory_leak_report.txt ReportTo = both
例子
#include <vld.h>
int main()
{
auto* p1 = new int;
auto* p2 = new int;
return 0;
}
检测报告
报告中显示了有两处内存泄漏,这是在 VS 中的输出窗口(CTRL + ALT + O)中,双击对应行即可定位到内存泄漏处
Linux 下检测内存泄漏的工具
mtrace检测内存泄露
mtrace其实是GNU扩展函数,用来跟踪malloc。
mtrace为内存分配函数(malloc, realloc, memalign, free)安装hook函数。这些hook函数记录内存的申请和释放的trace信息。
在程序中,这些trace信息可以被用来发现内存泄漏和释放不是申请的内存。
当调用mtrace,mtrace会检查环境变量MALLOC_TRACE。该环境变量应该包含记录trace信息的文件路径。如果文件可以被成功打开,它的大小被截断为0。
如果MALLOC_TRACE没有设置,或者设置的文件不可用或者不可写,那么将不会安装hook函数,mtrace不生效。
更对详细信息:man 3 mtrace
mtrace使用
mtrace 能监测程序是否内存泄露
-
在程序起始处包含
#include <mtrace.h>
-
更改环境变量:export MALLOC_TRACE=”mtrace.out”可以加入如下代码
-
setenv("MALLOC_TRACE", "mtrace.out", 1);
-
调用函数
mtrace()
-
编译程序时带上
-g
选项 -
运行程序一次,尽量调用所有程序内的函数。这时调试信息就已经被写入我们指定的 mtrace.out 文件中
-
mtrace a.out mtrace.out 查看内存监测情况
检测报告
Kmemleak 检测工具介绍
Kmemleak工作于内核态是内核自带的内核泄露检测工具, 其源代码位于mm/kmemleak.c
Kmemleak工作于内核态,Kmemleak 提供了一种可选的内核泄漏检测,其方法类似于跟踪内存收集器。当独立的对象没有被释放时,其报告记录在 /sys/kernel/debug/kmemleak中,Kmemcheck能够帮助定位大多数内存错误的上下文。
Kmemleak使用
-
首先
CONFIG_DEBUG_KMEMLEAK
在Kernel hacking
中被使能. -
查看内核打印信息详细过程如下:
-
挂载debugfs文件系统
mount -t debugfs nodev /sys/kernel/debug/
-
开启内核自动检测线程
echo scan > /sys/kernel/debug/kmemleak
-
查看打印信息
cat /sys/kernel/debug/kmemleak
-
清除内核检测报告,新的内存泄露报告将重新写入/sys/kernel/debug/kmemleak
echo clear > /sys/kernel/debug/kmemleak
-
内存扫描参数可以进行修改通过向/sys/kernel/debug/kmemleak 文件写入。 参数使用如下
off 禁用kmemleak(不可逆)
stack=on 启用任务堆栈扫描(default)
stack=off 禁用任务堆栈扫描
scan=on 启动自动记忆扫描线程(default)
scan=off 停止自动记忆扫描线程
scan=<secs> 设置n秒内自动记忆扫描
scan 开启内核扫描
clear 清除内存泄露报告
dump=<addr> 转存信息对象在<addr>
通过“kmemleak = OFF”,也可以在启动时禁用 Kmemleak 在内核命令行。在初始化 kmemleak 之前,内存的分配或释放这些动作被存储在一个前期日志缓冲区。这个缓冲区的大小通过配CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE设置。
Kmemleak动态检测原理
通过的 kmalloc、vmalloc、kmem_cache_alloc 等内存分配会跟踪其指针,连同其他的分配大小和堆栈跟踪信息,存储在 PRIO 搜索树。相应的释放函数调用跟踪和指针就会从 kmemleak 数据结构中移除。
分配的内存块,被认为是独立的,如果没有指针指向它起始地址或块的内部的任何位置,可以发现扫描内存(包括已保存的寄存器)。这意味着,有可能没有办法为内核通过所分配的地址传递块到一个释放函数,因此,该块被认为是一个内存泄漏。
扫描算法步骤:
-
标记的所有分配对象为白色(稍后将剩余的白色物体考虑独立的)
-
扫描存储器与所述数据片段和栈开始,检查对地址的值存储在PRIO搜索树。如果一个白色的对象的指针被发现,该对象将被添加到灰名单
-
扫描的灰色对象匹配的地址(一些白色物体可以变成灰色,并添加结束时的灰名单),直到黑色集结束
-
剩下的白色物体被认为是独立儿,并报告写入/sys/kernel/debug/kmemleak。
一些分配的内存块的指针在内核的内部数据结构和它们不能被检测为孤儿。对避免这种情况,kmemleak也可以存储的数量的值,指向一个内的块的地址范围内的地址,需要找到使块不被认为是泄漏.
kmem相关函数
函数 | 功能 |
---|---|
kmemleak_init | 初始化kmemleak |
kmemleak_alloc | 一个内存块分配的通知 |
kmemleak_alloc_percpu | 通知的一个percpu的内存块分配 |
kmemleak_free | 通知的内存块释放 |
kmemleak_free_part | 通知释放部分内存块 |
kmemleak_free_percpu | 一个percpu内存块释放的通知 |
kmemleak_not_leak | 当不是泄露时,标记对象 |
kmemleak_ignore | 当泄漏时不扫描或报告对象 |
kmemleak_scan_area | 添加扫描区域内的内存块 |
kmemleak_no_scan | 不扫描的内存块 |
kmemleak_erase | 删除一个指针变量的旧值 |
kmemleak_alloc_recursive | 为kmemleak_alloc,只检查递归 |
kmemleak_free_recursive | 为kmemleak_free,只检查递归 |