HOWTO: Debug Memory Leak in Android

在介紹如何 debug 之前,首先必須知道的是,目前的系統到底有沒有記憶體洩漏?以下先介紹幾個常用的記憶體觀察法:

  • cat /proc/meminfo      // 粗略的觀察目前記憶體的種類以及各個種類的大小
  • ps                             // 觀察每個 process 目前記憶體使用的情況 
  • top                            // 看看前幾個記憶體使用最多的 process 是哪些
  • dumpsys meminfo      // Android 特有的指令,有更多的資訊







方法1 Memory Analyzer :


這個方法必須配合 Eclipse 使用,因為 Memory Analyzer (MAT) 是 Eclipse 的一個 Plugin。
  1. 第一個步驟當然是安裝 MAT,安裝得方法有許多種,你可以下載MemoryAnalyzer-1.0.1.201008091353.zip,解開到Plugins,或者在Eclipse上點選 Help --> Install New Software... --> Add,然後在 Name 輸入 Memory Analyzer ,在 Location 輸入 http://download.eclipse.org/mat/1.0/update-site/ ,如圖所示:按下 OK,之後要選擇安裝 Plugin 完成安裝程序。
  2. 一如往常的執行你想要 debug 的 Android 程式,然後透過進入 shell 裡面檢查 /data/misc/ 這個目錄是否有可讀寫的權限,因為我們等一下會 dump file 到這個目錄。另外,也可以簡單的把他的權限設成 777:
    adb shell
    chmod 777 /data/misc/


  3. 接下來執行程式到你認為會產生 leak 的地方,來回多執行幾次,然後利用 kill 這個指令送信號 SIGUSR1 (-10) 給你的 process (可以透過 ps 查看 Process ID),假設你要 debug "com.test.debug" 這個 process :
    ps
    ...
    PID UID       VSZ  Stat Command
    100 1000   255255    S  com.test.debug
    ...
     
    kill -10 100


  4. 你可以透過 logcat 來確認你的 process 有沒有收到 signal:
    logcat &

    如果看到類似如下的訊息表示有收到:
    I/dalvikvm(  236): threadid=3: reacting to signal 10
    I/dalvikvm(  236): SIGUSR1 forcing GC and HPROF dump
    I/dalvikvm(  236): hprof: dumping VM heap to "/data/misc/heap-dump-tm1291081439-pid100.hprof-hptemp".
    I/dalvikvm(  236): hprof: dumping heap strings to "/data/misc/heap-dump-tm1291081439-pid100.hprof".
    I/dalvikvm(  236): hprof: heap dump completed, temp file removed
    D/dalvikvm(  236): GC_HPROF_DUMP_HEAP freed 585 objects / 60000 bytes in 10595ms
    查看一下 /data/misc/ 目錄應該可以看到 heap-dump-tm1291081439-pid100.hprof:
    ls /data/misc/
    ...
    heap-dump-tm1291081439-pid100.hprof
    ...


  5. 離開 shell
    exit

    透過 adb pull 把這個檔案抓下來。
    adb pull /data/misc/heap-dump-tm1291081439-pid100.hprof


  6. 透過 hprof-conv 把剛剛抓下來的檔案轉換成 Memory Analyzer 認識的格式:
    hprof-conv heap-dump-tm1291081439-pid100.hprof debug.hprof


  7. 開啟 Eclipse,點選 Window --> Open Perspective --> Other... ,然後選擇 Memory Analyer。
  8. 點選 File --> Open Heap Dump... ,然後選擇剛剛轉換過的檔案 (此例為 debug.hprof)。接著會出現一個對話框,詢問你想產生什麼樣的報告,如下圖:此時我們的目的是偵測 memory leak,所以自然是選擇 Leak Suspects Report,按下 Finish 後,就會產生一個報告,告訴你可疑的地方。是不是很棒呢!

方法2 libc_debug.so : 

這個方法基本上是將 libc.so 換成 libc_debug.so 利用 libc_debug.so 提供多項偵錯的功能來查看記事體是否被不當的使用。

  1. 將 /system/lib/libc.so 替換成 /system/lib/libc_debug.so
  2. 重啟系統 adb shell reboot 
  3. adb shell setprop libc.debug.malloc 1" (or 5, or 10 for slightly different behaviors)
  4. 新增 "native=true" 到你的 ~/.android/ddms.cfg 檔案中
  5. 啟動 stand-alone 版的 DDMS. 接著你應該會看到有 "Native Heap" tab 出現,切到這個頁面後就可以 native memory 的使用情況。
方法3 c/c++ debuuger : 

利用c/c++ debugger 來協助 debug c/c++ 層的 memory leak,接下的例子會使用 dmalloc 來 debug JNI native library.

  1. 先到 dmalloc 的官方網站 http://www.dmalloc.com 下載 source code。
  2. 交叉編譯 dmalloc,我個人是偏好用 Android NDK 來編譯,不過在這之前必須要先產生原本的 Makefile 然後照著 Makefile 來產生 Android.mk
    1. 執行 configure
      ?
      1
      . /configure --prefix= /arm-linux/ -- enable -cxx -- enable -threads
      其中/arm-linux/是隨便指定的路徑,反正我們只是想要參考 Makefile。
    2. 參考 Makefile,轉換成 Android.mk
    3. 執行 ndk-build 來編譯 dmalloc
  3. 因為我們是要 debug JNI 的 native library 所以沒辦法透過一般的設定環境變倏地方法來指定 debug options:
    ?
    1
    2
    DMALLOC_OPTIONS=debug=0x4e48503,inter=100,log= /sdcard/dmalloc .%p
    export DMALLOC_OPTIONS

    必須自行在程式進入點指定 debug option,以 JNI 為例,可以利用 JNI_OnLoad() 當作是進入點,此外,離開的時候也必須關閉:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "dmalloc.h"
     
    JNIEXPORT jint JNICALL JNI_OnLoad (
    ) {
         dmalloc_debug_setup ( "debug=0x4e48503,inter=100,log=/sdcard/dmalloc.%p" );
    }
     
    JNIEXPORT void JNICALL JNI_OnUnLoad (
    ) {
         dmalloc_shutdown ();
    }

    然後利用 dmalloc_mark() 與 dmalloc_log_changed() 來標記要偵錯的區段,下面我們以一個 JNI function 為例,故意造成 memory leak:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    unsigned long mark;
     
    JNIEXPORT void JNICALL JNI_com_example_debug_Test (
         JNIEnv* env,
         jobject thisArg
    ) {
         // Mark the start of debug
         mark = dmalloc_mark();
     
         // Leak memory 1000 bytes.
         char * leak = ( char *) malloc (1000);
     
         // log unfreed pointers that have been added to
         // the heap since mark
         dmalloc_log_changed (
             mark,
             1,    // log unfreed pointers
             0,    // do not log freed pointers
             1     // log each pnt otherwise summary
         );
    }

    一旦這個 function 被呼叫,就會在 /sdcard/ 目錄下產生類似 dmalloc.1000 (副檔名是這個process 的 PID),然後裡面就會告訴你那一行發生 memory leak了。
    ?
    1
    2
    3
    4
    5
    6
    948436802: 1: Dmalloc version '5.5.2' from 'http://dmalloc.com/'
    948436802: 1: flags = 0x4e48503, logfile 'logfile'
    948436802: 1: interval = 100, addr = 0, seen # = 0, limit = 0
    948436802: 1: starting time = 948436802
    948436802: 1: process pid = 1000
    ...
转帖:http://yindingtsai.blogspot.com/2010/11/howto-debug-memory-leak-in-android.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值