内存泄露bug指一个内存由操作系统或内部内存“池”分配,但是用完后从未收回。这实际上是资源回收的失职。有些人以为内存泄露只在支持内存分配并提供内存重分配方法的语言中出现。例如:C#和java不会导致这种错误,因为它们不支持内存分配,或者有一个垃圾收集机制,即在内存区长期不使用时自动释放。事实不只这么简单。资源泄露可以出现于任何语言,而且常常是因为编程错误而起。
症状:其症状往往是系统变慢或者突然崩溃,以及其他奇怪的症状。最容易发现的是系统的内存(或资源)在一段时间内减少而且不恢复。可以使用很多管理工具和命令、脚本等观察程序是否有内存泄露。
RSS: "Resident Set Size", 实际驻留"在内存中"的内存数. 不包括已经交换出去的代码. 举一个例子: 如果你有一个程序使用了100K内存, 操作系统交换出40K内存, 那么RSS为60K. RSS还包括了与其它进程共享的内存区域. 这些区域通常用于libc库等.
程序内存的信息(/proc/self/smaps):
VMSIZE: 15316 KB
RSS: 2560 KB total
1152 KB shared
428 KB private clean
980 KB private dirty
RSS(private dirty)最接近程序所使用的内存,特别是从heap分配的内存。
这也是我们最关心地方: 进程实际占用的内存数.
下面看一个C程序中常见的内存泄露错误(最简单的例子)。这种bug最讨厌,因为内存有时被收回,有时却没有。
test_memleak.cpp
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> int fun(void) { return (rand()>>3)%2; } int main() { srand( (unsigned)time(NULL)); int n=100; int *buffer=new int[n+1]; memset(buffer,0,n+1); if (fun())//sim error in the processing piece { printf("An error occurred.Skipping final stage\n"); return -1; } delete [] buffer; return 0; }
正常情况下,这段代码工作正常。如果某个业务处理没有错误,内存就会正常的释放。但如果出现错误,则不能被释放,就出现了泄露。当然使用过C++的人会告诉你使用“智能指针”,它们可以自动地释放自己所指向的内存。如果指针式全局的,没办法智能靠编程人员自动动手完成了。
作为测试人员通过哪些手段发现程序的内存泄露呢?查找内存泄露的工具至少二十种以上,以前用过DTrace,linux下改成systemtap,不过基本原理是一样的,感兴趣的请阅读我的其他文章,此工具使用起来还是比较麻烦。还有比较流行的工具Valgrind,大多数C程序员都接触过,个人感觉查找内存泄露过程中较大的影响应用的性能。看过google perftools工具箱中,提供Heap Checker堆内存泄漏检测工具,使用简单,并能够动态检测。
HeapChecker包括normal在内总共有4种泄漏检查方式:minimal,忽略进入main函数之前的初始化过程;normal,报告所有的无法再引用的内存对象;strick,在normal的基础上增加一些额外的检查;draconian,在程序退出的时候存在未释放的内存的情况下报错。
先在链接被检查程序的时候用-ltcmalloc选项连接GoolgePerftools的堆内存管理库tcmalloc(tcmalloc会替代C的堆内存管理库),然后每次用命令行“env HEAPCHECK=normal 可执行程序路径”来进行检查,其中检查形式normal可以替换成其他值,检查的结果会以屏幕报告的形式给出。
g++ -O0 -g test_memleak.cpp -ltcmalloc -o test_memleak
env HEAPCHECK=normal /root/src/test_memleak
[root@s144 src]# env HEAPCHECK=normal /root/src/test_memleak
WARNING: Perftools heap leak checker is active -- Performance may suffer
No leaks found for check "_main_" (but no 100% guarantee that there aren't any): found 17 reachable heap objects of 710 bytes
[root@s144 src]# env HEAPCHECK=normal /root/src/test_memleak
WARNING: Perftools heap leak checker is active -- Performance may suffer
No leaks found for check "_main_" (but no 100% guarantee that there aren't any): found 17 reachable heap objects of 710 bytes