26
2017
09

Android Native内存泄漏诊断

Android Native内存泄漏诊断

1、基础诊断方法

特点:操作简单,但只能判断是否有泄漏,但需使用者自行判断泄漏在哪里

命令行方式

adb shell dumpsys meminfo vStudio.Android.Camera360 -d

结果如图:
这里写图片描述

Android Studio

1、选中机器和进程,点击箭头所指按钮
这里写图片描述

2、点击Memory Usage
这里写图片描述

示例

例如,若需检测取景页是否有内存泄漏
先在首页检测一次
这里写图片描述
此时Native Heap占用20M

这里写图片描述
进入取景页再检测一次,此时占用53M
可见取景页目前占用了33M内存
然后反复进入同时检测,如果每次进入NativeHeap都有增加,那肯定是泄漏了

2、进阶诊断方法

假设前面确实检测出底层内存泄漏了,怎么办呢?
如果你是一个能把代码倒背如流的高手,同时灵光一闪,想起哪儿出的问题,那么恭喜你问题解决了
否则,我们还是借助工具进行下一步吧

背景

Android Studio 的DDMS 下有一个隐藏的功能 “native heap”,能够分析底层内存泄漏,但是这个玩意很难用,以下攻略都是围绕如何把它用起来

1、判断ROM是否支持

需要ROM里system/lib目录里有libc_malloc_debug_leak.so和libc_malloc_debug_qemu.so
最简单的判断方式是

adb shell getprop ro.build.type

有三种类型:
user、userdebug、eng
如果是user,那肯定不行,如果是后两者,恭喜你,可以进行下一步了
愿意倒腾的,可以尝试去刷机,CyanogenMod是userdebug
嫌麻烦的,直接用Android Studio的模拟器

2、下载Tools

native heap这个功能在API18之后就被删掉了,因此必须下载API18或之前的tools
Linux:https://dl-ssl.google.com/android/repository/tools_r18-linux.zip
Windows:https://dl-ssl.google.com/android/repository/tools_r18-windows.zip
Mac:https://dl-ssl.google.com/android/repository/tools_r18-macosx.zip
下载好之后,先备份一下原先sdk下面的tools目录,比如说改个名字什么的,然后把这个新的tools
目录放到sdk目录下

3、配置DDMS

Linux: ~.android\ddms.cfg
Windows:c:C:\Users\用户名.android\ddms.cfg
Mac:不知道
如果没找到这个文件的,先打开DDMS一次,就会生成这个文件
在里面加一行

native=true

4、设置参数

需要打开内存泄漏检测的开关

adb shell setprop libc.debug.malloc 1
adb shell stop
adb shell start

记得检查一下是否设置上

C:\Users\XXX>adb shell getprop libc.debug.malloc
1

看到返回1的话就是设置成功了
如果没成功,可能是需要root权限

5、开工

建议先关掉Android Studio,然后打开tools目录下的ddms
选中指定进程,然后点Snapshot Current Native Heap Usage
这里写图片描述
结果如下图
这里写图片描述
下面Stack Trace里面就是调用栈

6、调用栈解析

想要将调用栈解析为函数名及行号,首先需要带符号表的so库
然后按下列步骤:

C:\Users\XXX>adb shell getprop libc.debug.malloc
#adb shell
# ps|grep cc.zgeek.facedemo
u0_a47    8090  2232  533156 45976 ffffffff b6f1b5a8 R cc.zgeek.facedemo

获取到PID为8090

# cat /proc/8090/maps |grep libPinguoImageSDK.so
979aa000-987c8000 r-xp 00000000 fe:20 81935      /data/app-lib/cc.zgeek.facedemo
-1/libPinguoImageSDK.so
987c9000-9881d000 r--p 00e1e000 fe:20 81935      /data/app-lib/cc.zgeek.facedemo
-1/libPinguoImageSDK.so
9881d000-988b9000 rw-p 00e72000 fe:20 81935      /data/app-lib/cc.zgeek.facedemo
-1/libPinguoImageSDK.so

如果有多个,选r-xp的那个,可知内存起始地址为979aa000
以这两行为例
这里写图片描述

内存地址为:
97c5fc6c-979aa000= 2B5C6C
97c5218c-979aa000=2A818C

知道内存地址后,就可以通过llvm-symbolizer工具(clang编译)者addr2line工具(gcc编译)将内存地址转换成可读的源码文件地址与行数。
这些工具可以在ndk工具包的toolchains目录下找到
操作命令如下:

1、创建临时文件

vim tmp.txt

2、录入以下内容,并保存
libPinguoImageSDK.so 0x2B5C6C
libPinguoImageSDK.so 0x2A818C
3、执行命令

llvm-symbolizer < tmp.txt

4、命令行输出内容即为内存地址与源码地址的对应关系,比如
void pugi::impl::(anonymous namespace)::xpath_ast_node::step_fill<pugi::impl::(anonymous namespace)::axis_to_type<(pugi::impl::(anonymous namespace)::axis_t)7> >(pugi::impl::(anonymous namespace)::xpath_node_set_raw&, pugi::xml_attribute const&, pugi::xml_node const&, pugi::impl::(anonymous namespace)::xpath_allocator*, pugi::impl::(anonymous namespace)::axis_to_type<(pugi::impl::(anonymous namespace)::axis_t)7>)
/Users/camera360/Documents/projects/c360/PGMakeupDemo/app/src/main/PinguoImageSDK_Android_OpenGL/ImageSDK/pugixml.cpp:7855:0

pugi::impl::(anonymous namespace)::utf_decoder<pugi::impl::(anonymous namespace)::utf8_counter, pugi::impl::(anonymous namespace)::opt_false>::decode_wchar_block(wchar_t const*, unsigned int, unsigned int)
/Users/camera360/Documents/projects/c360/PGMakeupDemo/app/src/main/PinguoImageSDK_Android_OpenGL/ImageSDK/pugixml.cpp:1000:11

可见,前面图中
这里写图片描述
这一行总计3044053bytes=2.9MB的空间被用于存储xml解析数据
如果退出相应界面之后这部分空间仍然存在,则可以认为是内存泄漏

上一篇:Android自定义View之属性解析 下一篇:自定义可点击和滑动的按钮