Native内存调试,或许大部分Android开发者不怎么能接触到这一块,因为Native一般由底层C++工程师进行调试的,如果从事Android系统开发的哥们应该会用得到这一块。所以这个方向在网上的资料比较少,谷歌官方在Android开发者网站(developer.android.com)提到的内存调试仅限于JAVA层。官方只有在Android Open Source Project网站(source.android.com)上才有提及Naitve内存调试的相关信息。好了,废话就说到这了。现在开始着手Naive内存调试的开始。
本文需要使用到的工具有
1、Android Sdk
2、Android Emulator(Sdk里有)
3、NDK(https://dl.google.com/android/repository/android-ndk-r12b-linux-x86_64.zip)
4、DDMS(https://dl.google.com/android/repository/tools_r25.2.3-linux.zip)
当然,还有android项目,so库等,这些就不一一列举了,毕竟本文的重点是内存调试。注:本文开发环境是linux。所以(NDK和DDMS)下载地址仅限linux环境。
一、DDMS解除封印,“Native Heap”选项开启
在安卓开放源码项目(https://source.android.com/devices/tech/debug/native-memory)中提到。
You can also use the Dalvik Debug Monitor Server (DDMS) to obtain a graphical view of Malloc Debug output.
To use DDMS, first turn on its native memory UI:
Open
~/.android/ddms.cfg
Add the line:
native=true
意思就是说打开当前用户配置目录下的.android目录里的文件ddms.cfg配置文件进行修改。
在文件记录的末尾新增一行,加上native=true。修改保存后,重启ddms即可。(window环境下是在C:\Documents and Settings\$user\.android\ddms.cfg)
Native Heap如图所示
二、打开模拟器,打开模拟器malloc的debug模式
在终端输入以下命令:
adb shell setprop libc.debug.malloc 1
adb shell stop
adb shell start
这个阶段模拟器会进行重启。这里特别说明一下为什么教程不用真机进行,因为真机/system/lib目录下没有debug版本的malloc库( libc_malloc_debug_leak.so 和 libc_malloc_debug_qemu.so)。如果一定要使用真机调试的话,可以从原生系统的模拟器或者真机中拷贝这2个库,然后赋予0644权限,再调用以上命令即可。
三、进行Native内存调试
打开DEMO项目,点击New 100M MEMORY的Button。我在Button调用的Native方法里面申请了100M的运行内存,并且不进行释放。用于模拟Native内存泄漏的情况。
选择DEMO的运行进程com.example.spence.myapplicationcplus,然后在ddms中点击snapshot current native heap usage按钮。
这时出现了一个错误提示,提示讲找不到本地的库文件,我们点ok后。如图所示
可以看到Native heap选项窗口中展示了目前内存占用的情况,以及调用的次数。method方法名这个时候显示的是在当前运行系统中内存的地址。这么看不够直观。那么我们来让显示变得更直观一点。
四、进行NDK地址映射
NDK里面有个好东西可以帮助我们让方法显示更直观。那就是NDK里的arm-linux-androideabi-addr2line工具。要使用这个工具,必须配置此工具路径到环境变量。arm-linux-androideabi-addr2line工具的路径为android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin
配置完环境变量后,还需要在Symbol Search Path填入so库的名字,此处填入DEMO项目的so库路径MyApplicationCPlus/app/build/intermediates/cmake/debug/obj/x86/即可。
然后再点击snapshot current native heap usage按钮。出现如下图所示。
这次我们可以看到已经清晰的显示出了Method的名称,并且在Stack Track窗口还显示了具体调用代码的行号。便于我们对相关占用内存的代码进行查看。
DEMO工程里的Native代码目前是内存泄漏的,例如我们再点击New 100M MEMORY的Button3次,那么会得到如下图所示
我们可以看到Library窗口中,DEMO工程的SO库方法Java_com_example_spence_myapplicationcplus_MainActivity_stringFromJNI显示Count为4,这代表目前被调用了4次。也就是说通过定位代码方法和次数,可以进行Native内存泄漏的检测。
注:如果项目中有多个so库,在Symbol Search Path中用:进行隔开路径就好,如果都在同一目录下就不需要隔开。
如果有什么不明白的欢迎大家留言提问。
DEMO工程的下载链接: https://pan.baidu.com/s/1qXLAv9q 密码: ftq8