在最近的一个Android项目里,发现我们的ref-app有持续的内存增长。java部分因为有GC,所以不会有leak的可能,native部分代码量很大,所以native heap leak的可能性是比较大的。当然大家首先想到的就是Valgrind利器。因为以前用过Valgrind扫描内存污染,所以这次就很快上手了。啥也不说,先上log:
345,664 bytes in 1 blocks are possibly lost in loss record 395 of 400
at 0x4806920: malloc (vg_replace_malloc.c:270)
by 0x2296A4E3: CXXXHeapMem::DoAllocate(unsigned int, unsigned int&) (WXXX.cpp:219)
by 0x2296A1FB: CXXXAlignedMem::Allocate(unsigned int) (WXXX.cpp:122)
by 0x22A20FF7: CXXXAllocator::GetXXX(unsigned long) (WXXX.cpp:260)
这是一个很清楚的调用堆栈。其实刚开始并没有这个堆栈,只有
vg_replace_malloc这个层次的信息。我从网上得知用debug方式编译的库就会有调用堆栈了,于是我应用APP_OPTIM:=debug
重编了所有的so,并选用obj/local/armeabi-v7a下面的so(注意,这个路径下的so才是真正带有gdb信息的so,跟debug/release文件夹无关)。于是再次用valgrind扫描的时候就出现调用堆栈了。但是,并不是所有的leak都有调用堆栈,有些依旧没有详细信息,不知道为什么。分享一个链接:
http://www.linuxprogrammingblog.com/using-valgrind-to-debug-memory-leaks
接下来要理解valgrind的描述,最好能猜到它是在描述哪种情形。关于描述,常见这么几种:
definitely lost,indirectly lost,possibly lost,
still reachable。官方对它们有解释,参见: 。我对它们的理解是,definitely lost和indirectly lost是绝对的内存泄漏,程序员代码的问题,必须要改掉的。possibly lost和still reachable跟程序员对内存的使用有关,或许不是泄漏,例如,全局变量指向的一块buffer,当程序退出时这块buffer由OS负责释放,Valgrind对此无能为力只能认为是“可能”泄漏了。但是这并不意味着我们可以忽视possibly lost和still reachable,因为Valgrind是久经沙场的值得信赖的工具,它指出的“可能”其实是有很大leak嫌疑的,要我们去排查的。我自己对“possibly lost/still reachable“的描述是:runtime期间所有在全局变量里保存过的指针如果发生了指针偏移又没有最后主动释放,那就是possbile loss;如果没有发生偏移又没有主动释放,那就是still reachable。举个例子,假如我们有个全局的list,它保存过一个对象的指针(已经是偏移过后的指针),后来该指针被从list里移除了,但是对象忘记释放了,Valgrind会认为这是possible lost,虽然在程序退出时list里已经没有保存这个对象的指针了。
Valgrind会告诉我在哪里分配的内存没有释放,但是不会告诉我谁用了不释放。要靠自己想办法找到谁没有释放,相信这不难的。
阅读(1802) | 评论(0) | 转发(0) |