android sources全局指导坐镇
https://source.android.com/devices/tech/debug/native-memory
一直没有实践native进程的内存泄漏问题的debug,网上也一直没找到有用的。直到遇到heapsnap,发现真是有用,至此一块心病也是解决了。再加上之前用asan来分析userspace的内存问题,可以说稳定性这块关于内存的算是有初步的把握了。后续就是需要对内核关于内存的优化有更多的学习和总结。
验证Android版本为P
1.用malloc debug发现内存非法使用问题
setprop libc.debug.malloc.options backtrace
setprop libc.debug.malloc.program vendor/bin/test
11-15 10:29:51.406 4573 4573 I malloc_debug: ./vendor/bin/test: Run: 'kill -47 4573' to dump the backtrace.
11-15 10:29:51.408 4573 4573 I libc : ./vendor/bin/test: malloc debug enabled
11-15 10:29:51.410 4573 4573 D : test main
11-15 10:29:51.410 4573 4573 D TEST : test begin1
11-15 10:29:51.410 4573 4573 D TEST : double free
11-15 10:29:51.410 4573 4573 E TEST : afte free test1: -1345756352
11-15 10:29:51.410 4573 4573 E TEST : afte free test2 99
11-15 10:29:51.410 4573 4573 E malloc_debug: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-15 10:29:51.410 4573 4573 E malloc_debug: +++ ALLOCATION 0xafc8c018 UNKNOWN POINTER (free)
11-15 10:29:51.410 4573 4573 E malloc_debug: Backtrace at time of failure:
11-15 10:29:51.410 4573 4573 E malloc_debug: #00 pc 00000d08 /vendor/lib/libtest.so (doTest()+71)
11-15 10:29:51.410 4573 4573 E malloc_debug: #01 pc 00088f54 /system/lib/libc.so (__libc_init+47)
11-15 10:29:51.410 4573 4573 E malloc_debug: #02 pc 00000ba2 /vendor/bin/test
11-15 10:29:51.411 4573 4573 E malloc_debug: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-15 10:29:51.411 4573 4573 E TEST : afte free 2 times
an.xi@droid01:/mnt/fileroot/an.xi/p$ addr2line -ife out/target/product/ampere/symbols/vendor/lib/libtest.so 00000d08
_Z6doTestv
vendor/amlogic/common/system/libtest/testlib.cpp:34
30 free (buf_);
31 ALOGE("afte free test1: %d\n",buf_->test1);
32 buf_->test2 = 99;
33 ALOGE("afte free test2 %d\n",buf_->test2);
34 free (buf_); -----
35 ALOGE("afte free 2 times \n");
检测到的是两次free,并且use after free没有检测出来,因为这只是打栈。
2.用malloc debug发现内存泄漏
setprop libc.debug.malloc.options leak_track
setprop libc.debug.malloc.program vendor/bin/test
11-15 10:39:42.332 4594 4594 I malloc_debug: vendor/bin/test: Run: 'kill -47 4594' to dump the backtrace.
11-15 10:39:42.334 4594 4594 I libc : vendor/bin/test: malloc debug enabled
11-15 10:39:42.336 4594 4594 D : test main
11-15 10:39:42.336 4594 4594 D TEST : test begin1
11-15 10:39:42.336 4594 4594 D TEST : double free
11-15 10:39:42.336 4594 4594 E TEST : afte free test1: 101
11-15 10:39:42.336 4594 4594 E TEST : afte free test2 99
11-15 10:39:42.336 4594 4594 E TEST : afte free 2 times
11-15 10:39:42.336 4594 4594 E malloc_debug: +++ vendor/bin/test leaked block of size 48 at 0xa7b1a540 (leak 1 of 5)
11-15 10:39:42.336 4594 4594 E malloc_debug: Backtrace at time of allocation:
11-15 10:39:42.337 4594 4594 E malloc_debug: #00 pc 00009b66 /system/lib/vndk-sp-28/libutils.so (android::SharedBuffer::alloc(unsigned int)+13)
11-15 10:39:42.337 4594 4594 E malloc_debug: #01 pc 0000d55e /system/lib/vndk-sp-28/libutils.so (android::VectorImpl::_grow(unsigned int, unsigned int)+285)
11-15 10:39:42.337 4594 4594 E malloc_debug: #02 pc 0000daba /system/lib/vndk-sp-28/libutils.so (android::VectorImpl::add(void const*)+13)
11-15 10:39:42.337 4594 4594 E malloc_debug: #03 pc 0000e40e /system/lib/vndk-sp-28/libutils.so (android::add_sysprop_change_callback(void (*)(), int)+93)
11-15 10:39:42.337 4594 4594 E malloc_debug: +++ vendor/bin/test leaked block of size 20 at 0xa7b08ac8 (leak 2 of 5)
11-15 10:39:42.337 4594 4594 E malloc_debug: Backtrace at time of allocation:
11-15 10:39:42.337 4594 4594 E malloc_debug: #00 pc 0004365c /system/lib/vndk-sp-28/libc++.so (operator new(unsigned int)+15)
11-15 10:39:42.337 4594 4594 E malloc_debug: #01 pc 0000e3d4 /system/lib/vndk-sp-28/libutils.so (android::add_sysprop_change_callback(void (*)(), int)+35)
11-15 10:39:42.337 4594 4594 E malloc_debug: +++ vendor/bin/test leaked block of size 5 at 0xa7b0c010 (leak 3 of 5)
11-15 10:39:42.337 4594 4594 E malloc_debug: Backtrace at time of allocation:
11-15 10:39:42.337 4594 4594 E malloc_debug: #00 pc 0000c508 /system/lib/liblog.so
11-15 10:39:42.337 4594 4594 E malloc_debug: #01 pc 0000c36e /system/lib/liblog.so (__android_log_is_loggable_len+9)
11-15 10:39:42.337 4594 4594 E malloc_debug: #02 pc 0000724e /system/lib/liblog.so
11-15 10:39:42.337 4594 4594 E malloc_debug: #03 pc 00006b6a /system/lib/liblog.so (__android_log_buf_write+249)
11-15 10:39:42.337 4594 4594 E malloc_debug: #04 pc 00006c9e /system/lib/liblog.so (__android_log_print+65)
11-15 10:39:42.337 4594 4594 E malloc_debug: #05 pc 00000c76 /vendor/lib/libtest.so (doTest()+13)
11-15 10:39:42.337 4594 4594 E malloc_debug: #06 pc 00088f54 /system/lib/libc.so (__libc_init+47)
11-15 10:39:42.337 4594 4594 E malloc_debug: #07 pc 00000ba2 /vendor/bin/test
11-15 10:39:42.337 4594 4594 E malloc_debug: +++ vendor/bin/test leaked block of size 4 at 0xa7b0c008 (leak 4 of 5)
11-15 10:39:42.337 4594 4594 E malloc_debug: Backtrace at time of allocation:
11-15 10:39:42.338 4594 4594 E malloc_debug: #00 pc 0005b010 /system/lib/libc.so
11-15 10:39:42.338 4594 4594 E malloc_debug: #01 pc 000223ea /system/lib/libc.so (newlocale+93)
11-15 10:39:42.338 4594 4594 E malloc_debug: #02 pc 00069142 /system/lib/libc++.so
11-15 10:39:42.338 4594 4594 E malloc_debug: #03 pc 0006ea34 /system/lib/libc++.so (std::__1::locale::__global()+119)
11-15 10:39:42.338 4594 4594 E malloc_debug: #04 pc 0006eab4 /system/lib/libc++.so (std::__1::locale::locale()+3)
11-15 10:39:42.338 4594 4594 E malloc_debug: #05 pc 0004d82c /system/lib/libc++.so (std::__1::basic_streambuf
11-15 10:39:42.338 4594 4594 E malloc_debug: #06 pc 00054482 /system/lib/libc++.so
11-15 10:39:42.338 4594 4594 E malloc_debug: #07 pc 000540d8 /system/lib/libc++.so (std::__1::ios_base::Init::Init()+23)
11-15 10:39:42.338 4594 4594 E malloc_debug: #08 pc 0003276a /system/lib/libc++.so
11-15 10:39:42.338 4594 4594 E malloc_debug: +++ vendor/bin/test leaked block of size 4 at 0xa7b0c028 (leak 5 of 5)
11-15 10:39:42.339 4594 4594 E malloc_debug: Backtrace at time of allocation:
11-15 10:39:42.340 4594 4594 E malloc_debug: #00 pc 0005b010 /system/lib/libc.so
11-15 10:39:42.340 4594 4594 E malloc_debug: #01 pc 000223ea /system/lib/libc.so (newlocale+93)
11-15 10:39:42.340 4594 4594 E malloc_debug: #02 pc 00069102 /system/lib/vndk-sp-28/libc++.so
11-15 10:39:42.340 4594 4594 E malloc_debug: #03 pc 0006e9f4 /system/lib/vndk-sp-28/libc++.so (std::__1::locale::__global()+119)
11-15 10:39:42.340 4594 4594 E malloc_debug: #04 pc 0006ea74 /system/lib/vndk-sp-28/libc++.so (std::__1::locale::locale()+3)
11-15 10:39:42.340 4594 4594 E malloc_debug: #05 pc 0004d7ec /system/lib/vndk-sp-28/libc++.so (std::__1::basic_streambuf
11-15 10:39:42.340 4594 4594 E malloc_debug: #06 pc 00054442 /system/lib/vndk-sp-28/libc++.so
11-15 10:39:42.340 4594 4594 E malloc_debug: #07 pc 00054098 /system/lib/vndk-sp-28/libc++.so (std::__1::ios_base::Init::Init()+23)
11-15 10:39:42.340 4594 4594 E malloc_debug: #08 pc 0003274a /system/lib/vndk-sp-28/libc++.so
addr2line -ife out/target/product/xxxx/symbols/vendor/lib/libtest.so 00000c76
_Z6doTestv
vendor/xxx/common/system/libtest/testlib.cpp:14
14 ALOGD("test begin1");
15 void *p = malloc(sizeof(char) * 10);
①指出的是那块内存没有被释放。
②malloc_debug是在程序运行结束之后才打印出来。
替换library就不用重启了
3.结合heapsnap debug native内存泄漏
malloc debug只有当native进程退出的时候才能检测出来是不是有泄漏,但是怎么个退出法也没说,kill -9肯定是不行的。
验证发现github上面的heapsnap可以满足这方面的需求, 使用的是LD_PRELOAD加载动态库libheapsnap.so方式
和read.me上有差异,因为照搬的话有问题。
heapsnap地址
https://github.com/albuer/heapsnap
①准备工作,将编译的libheap.so push到vendor/lib,确保和二进制文件如vendor/bin/test在同一namespace
adb push libheapsnap.so vendor/lib/libheapsnap.so
adb shell chmod 0644 /data/local/tmp/libheapsnap.so
adb shell mkdir -p /data/local/tmp/heap_snap
adb shell chmod 0777 /data/local/tmp/heap_snap
②开启malloc debug调试
setprop libc.debug.malloc.options backtrace
setprop libc.debug.malloc.program vendor/bin/test
③配置LD_PRELOAD环境变量
export LD_PRELOAD=vendor/lib/libheapsnap.so
④执行目标进程
stop vendor/bin/test
vendor/bin/test
⑤通过signal 21获取目标进程的heap信息,并自动保存文件到/data/local/tmp/heap_snap/目录下
kill -21
⑥分析proc_3968_0000.heap,反编译等。
通过占有的内存大小排序和对应的栈,可以直接拿到对应的嫌疑代码行,从而定位问题。
Heap Snapshot v0.2
Total memory: 1167480
Allocation records: 8
size 4096, dup 285, 0xafd8bd4a, 0xaff98f54, 0x8b344ba2
#00 pc 00000d4a /vendor/lib/libtest.so (doTest()+85)
#01 pc 00088f54 /system/lib/libc.so (__libc_init+47)
#02 pc 00000ba2 /vendor/bin/test
size 48, dup 1, 0xafe98b66, 0xafe9c55e, 0xafe9caba, 0xafe9d40e
#00 pc 00009b66 /system/lib/vndk-sp-28/libutils.so (android::SharedBuffer::alloc(unsigned int)+13)
#01 pc 0000d55e /system/lib/vndk-sp-28/libutils.so (android::VectorImpl::_grow(unsigned int, unsigned int)+285)
#02 pc 0000daba /system/lib/vndk-sp-28/libutils.so (android::VectorImpl::add(void const*)+13)
#03 pc 0000e40e /system/lib/vndk-sp-28/libutils.so (android::add_sysprop_change_callback(void (*)(), int)+93)