天天看點

利用Wrap Shell Script定位Android Native記憶體洩漏

前提條件

  • 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

這時我以擷取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

再次打開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的記憶體配置設定是否發生了洩漏及哪些地方導緻了記憶體洩漏