Android开发——使用DDMS分析Native层内存泄漏
针对Java层的内存泄漏,Android提供了方便的内存泄漏检测工具,例如MAT、LeakCanary。但对于native层开发,要追查C/C++代码的内存泄漏,valgrind等常用工具并不适用。幸好,Google的bionic库提供了新的方法。下面就介绍如何利用DDMS分析Native层的内存泄漏。
所有的Native内存分配函数(malloc,calloc,etc.)都在Android的libc库中。为了跟踪堆内存的分配,需要使用这个库的特别版本,可以将每次内存开销记录下来。这些特殊版本的libc(libc_malloc_debug_leak.so和libc_malloc_debug_qemu.so,在/system/lib 下查看是否有这两个库 ) 。
内存调试靠读取 build.prop 文件中的配置属性 libc.debug.malloc 来控制的,属性值含义如下:
bionic/libc/bionic/malloc_debug_common.c
libc.debug.malloc 1 检测内存泄漏
libc.debug.malloc 5 分配的内存用0xeb填充,释放的内存用0xef填充
libc.debug.malloc 10 内存分配打pre-和post- 的桩子,可以检测内存的overruns
libc.debug.malloc 20 SDK模拟器上检测内存用
为了开机就启动,可以在开机的时候就设置属性。在build.prop文件中写入libc.debug.malloc属性:
#adb remount
#vi system/build.prop
增加 libc.debug.malloc=1属性
或者:
#adb remount
#adb shll
#echo "libc.debug.malloc=1">> system/build.prop
在C盘用户的目录下:
~\.android\ ddms.cfg
打开ddms.cfg进行编辑,写入:
native=true
在\sdk\tools目录下打开ddms.bat
示意图说明:
1、选中应用进程;
2、打开:Show heap updates,显示堆内存更新;
3、选择:Native heap,Native层堆内存;
4、Snapshot Current Native Heap Usage:抓取内存快照;
5、选择:Group allocations by library ,按照库来显示内存分配;
6、选择:抓取增量(抓取相对于前一次内存快照的增量);
7、选择:Show zygote allocations ,选择源始进程的内存分配;
如果按下±(增量)按钮,在点击 Snapshot Current Native Heap Usage 可以比较两次抓取内存之间新分配了哪些空间。查看这个增量结果,通常Percentage和Count值较高的地方都是有可能存在内存泄漏的地方。查看Library项可以拿到可疑库的地址Addr(比如:413afa96)
也有可能直接在DDMS页面的Stack Trace直接查看代码定位:
从内存快照中拿到的地址的并不能用来直接定位到分配内存的地方。还需要计算库的物理地址偏移量。
以查找 com.android.browse r的 libwebviewchromium.so 库为例:
#adb shell
#ps|grep com.android.browser
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a18 2571 1883 1423100 93768 ffffffff b7668cdb S com.android.browser
#cat /proc/2571/maps |grep libwebviewchromium.so
8284f000-82942000 r--p 41391000 08:06 918 /system/lib/libwebviewchromium.so
由此计算其指令在文件内的偏移量:
0x413afa96 - 0x41391000 = 0x1ea96
然后用addr2line就可以查看这条指令对应的源码在哪个文件的哪个位置:
$ arm-linux-androideabi-addr2line -e
out/target/product/sp8825ea/symbols/system/lib/libwebviewchromium.so 0x1ea96
1、打开DDMS后发现目标应用的进程信息没有显示
解决方案是:
在注册文件的application标签下打开debuggable属性:
2、整个分析过程要保证ADB不会断开连接;
3、抓取内存快照时DDMS的过程中不要最好不要操作设备,否则可能很容易导致ANR。
参考文章:
Android中native进程内存泄露的调试技巧
Android 内存检测
Android native heap memory leak 实战(二) — DDMS