前提條件
- Android版本為8.0以上
環境配置
- cd到/src/main目錄下,新建shell目錄,同時shell目錄下配置與libs目錄下相同平台的目錄,如下app下的層級結構,可看到shell/lib下具有與libs下相同的平台目錄結構
── AndroidManifest.xml
├── java
├── libs
│ ├── arm64-v8a
│ └── armeabi-v7a
├── main.iml
├── res
└── shell
└── lib
├── arm64-v8a
└── armeabi-v7a
- 分別在shell/lib/目錄下建立一個wrap.sh腳本文件,編輯wrap.sh文件並寫入如下內容
#!/system/bin/sh
LIBC_DEBUG_MALLOC_OPTIONS=backtrace $@
並賦予腳本其執行權限chmod +x wrap.sh
注意,如果你最終生成的apk是隻需要armeabi-v7a的,則不要在arm64-v8a中放置wrap.sh腳本文件。
- 打開/build.gradle文件,在sourceSets.main增加資源文件路徑,如
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir "src/main/libs"
resources.srcDir "src/main/shell"
}
- 環境配置完成,編譯打包apk,使用Android Studio分析apk,確保相應平台裏存在wrap.sh腳本文件
獲取Native內存分配信息
- 安裝運行apk,並獲取pid
- 對app執行一系列操作,由於此時內存分配時會執行更多的操作,app運行速度可能減慢
- 終端上執行如下命令,
adb shell am dumpheap -n <pid> /data/local/tmp/heap.txt
- 將/data/local/tmp/heap.txt pull到本地,打開heap.txt可看到一些信息,如下
Android Native Heap Dump v1.0
Total memory: 38937197
Allocation records: 42720
Backtrace size: 16
z 1 sz 20039040 num 1 bt edeff75a edeff654 edeff73e ee44d99a efda71f0 ee4487a4
z 1 sz 3908764 num 1 bt d2a28a38 d2a332b0 d290977a d28f9d96
z 1 sz 520192 num 1 bt cd30ca40 cd2b3ce8 cd2c307a cd2c2e50 cd2c2c24 cd2bca9e ee5cbdac ce546204 ce54d022 ce54f95c ce54ad92 ce53c1b4 ce53c1da ce5dab22 ee2ca8d6 ee29e340
......
- 下載文件native_heapdump_viewer.py,如果你終端無法直接訪問addr2line和objdump兩個命令,則需要將python腳本中兩命令替換為ndk的路徑訪問,如
<ndk path>toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump
<ndk path>toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line
- 使用如下命令對抓到取的native內存分配信息進行符號分析
python native_heapdump_viewer.py --symbols . heap.txt > heapinfo.txt
加--html 生成html格式便于分析
這時我以獲取libQuCore.so庫的內存分配信息為例,--symbols是設置給腳本文件路徑,注意此時打開heapinfo.txt可能無法獲取到正確的地址和文件匹配信息,比如會收到類似如下的信息
/data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so not found for symbol resolution
2521990 6.72% 92.18% 409 ce5dab22 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so ??? ???
2520966 6.72% 99.96% 408 ce53c1da /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so ??? ???
2519574 6.71% 99.94% 381 ce53c1b4 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so ??? ???
2519574 6.71% 100.00% 381 ce54ad92 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so ??? ???
2519414 6.71% 99.99% 379 ce54f95c /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so ??? ???
2517560 6.71% 99.93% 351 ce54d022 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so ??? ???
2500576 6.66% 99.33% 160 ce546204 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so ??? ???
這是因為android需要與手機庫路徑完全一樣的符號文件路徑,於是我們在本地新建一個與上述獲取到的手機上的相同的路徑並將libQuCore.so拷貝到新建的路徑下,假設此路徑位於symbols目錄下,如symbols/data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so路徑存在,重新執行上述符號解析命令python native_heapdump_viewer.py --symbols symbols heap.txt > heapinfo.txt
或者将heap.txt 中的
s/data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm 前缀删除,只留下QuCore.so,然后symbols 替换成symbol 文件所在目录
再次打開heapinfo.txt文件,可以獲取libQuCore.so相關的符號與文件、行數匹配的信息了,如下摘取了一部分示例
2521990 6.72% 92.18% 409 ce5dab22 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so execute_native_thread_routine /Volumes/Android/buildbot/src/android/ndk-r14-release/toolchain/gcc/gcc-4.9/libstdc++-v3/src/c++11/thread.cc:84
2520966 6.72% 99.96% 408 ce53c1da /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so std::thread::_Impl<std::_Bind_simple<void (*(alivc::ThreadService*))(alivc::ThreadService*)> >::_M_run() /Users/xunshan/Library/Android/sdk/android-ndk-r14b/sources/cxx-stl/gnu-libstdc++/4.9/include/functional:1700 (discriminator 2)
2519574 6.71% 99.94% 381 ce53c1b4 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so alivc::ThreadWorker(alivc::ThreadService*) /Users/xunshan/Desktop/AliyunSVideo-product/sources/native/modules/alivc_framework/src/mdf/service/thread_service.cpp:18
2519574 6.71% 100.00% 381 ce54ad92 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so alivc::RenderEngineService::OnInit() /Users/xunshan/Desktop/AliyunSVideo-product/sources/native/modules/alivc_framework/src/render_engine/render_engine_service.cpp:284
2519414 6.71% 99.99% 379 ce54f95c /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so alivc::Canvas::Init() /Users/xunshan/Desktop/AliyunSVideo-product/sources/native/modules/alivc_framework/src/render_engine/canvas.cpp:36 (discriminator 1)
2517560 6.71% 99.93% 351 ce54d022 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so alivc::GraphicContext::Init(void*) /Users/xunshan/Desktop/AliyunSVideo-product/sources/native/modules/alivc_framework/src/render_engine/render_system/GL/graphic_context.cpp:36
2500576 6.66% 99.33% 160 ce546204 /data/app/com.aliyun.apsaravideo-e1DYx-Wua0VifW_TwlHhAw==/lib/arm/libQuCore.so alivc::AlivcEGLContext::Init(void*) /Users/xunshan/Desktop/AliyunSVideo-product/sources/native/modules/alivc_framework/src/render_engine/render_system/EGL/egl_context.cpp:59
- 針對上述獲取到的內存分配對應的文件和行數解析的信息,可以分析native的內存分配是否發生了泄漏及哪些地方導致了內存泄漏