1. 程式人生 > >Android開發————分析Native層記憶體洩漏

Android開發————分析Native層記憶體洩漏

Android開發——使用DDMS分析Native層記憶體洩漏

針對Java層的記憶體洩漏,Android提供了方便的記憶體洩漏檢測工具,例如MAT、LeakCanary。但對於native層開發,要追查C/C++程式碼的記憶體洩漏,valgrind等常用工具並不適用。幸好,Google的bionic庫提供了新的方法。下面就介紹如何利用DDMS分析Native層的記憶體洩漏。

檢查是否有 libc_malloc_debug_leak.so

所有的Native記憶體分配函式(malloc,calloc,etc.)都在Android的libc庫中。為了跟蹤堆記憶體的分配,需要使用這個庫的特別版本,可以將每次記憶體開銷記錄下來。這些特殊版本的libc(libc_malloc_debug_leak.so和libc_malloc_debug_qemu.so,在/system/lib 下檢視是否有這兩個庫 ) 。

配置build.prop中的libc.debug.malloc屬性值

記憶體除錯靠讀取 build.prop 檔案中的配置屬性 libc.debug.malloc 來控制的,屬性值含義如下:

        bionic/libc/bionic/malloc_debug_common.c

        libc.debug.malloc    1    檢測記憶體洩漏
        libc.debug.malloc    5    分配的記憶體用0xeb填充,釋放的記憶體用0xef填充
        libc.debug.malloc    10   記憶體分配打pre-和post- 的樁子,可以檢測記憶體的overruns
        libc.debug.malloc    20   SDK模擬器上檢測記憶體用

為了開機就啟動,可以在開機的時候就設定屬性。在build.prop檔案中寫入libc.debug.malloc屬性:

         #adb remount
         #vi system/build.prop  
         增加 libc.debug.malloc=1屬性

或者:

        #adb remount
        #adb shll
        #echo "libc.debug.malloc=1">> system/build.prop

配置DDMS

配置ddms.cfg

在C盤使用者的目錄下:

        ~\.android\ ddms.cfg 

開啟ddms.cfg進行編輯,寫入:

        native=true

開啟DDMS

在\sdk\tools目錄下開啟ddms.bat

使用DDMS抓取記憶體快照

DDMS使用說明

        示意圖說明:
        1、選中應用程序;
        2、開啟:Show heap updates,顯示堆記憶體更新;
        3、選擇:Native heap,Native層堆記憶體;
        4、Snapshot Current Native Heap Usage:抓取記憶體快照;
        5、選擇:Group allocations by library ,按照庫來顯示記憶體分配;
        6、選擇:抓取增量(抓取相對於前一次記憶體快照的增量);
        7、選擇:Show zygote allocations ,選擇源始程序的記憶體分配;

這裡寫圖片描述

如果按下±(增量)按鈕,在點選 Snapshot Current Native Heap Usage 可以比較兩次抓取記憶體之間新分配了哪些空間。檢視這個增量結果,通常Percentage和Count值較高的地方都是有可能存在記憶體洩漏的地方。檢視Library項可以拿到可疑庫的地址Addr(比如:413afa96)

也有可能直接在DDMS頁面的Stack Trace直接檢視程式碼定位:
這裡寫圖片描述

通過記憶體地址定位洩漏點

從記憶體快照中拿到的地址的並不能用來直接定位到分配記憶體的地方。還需要計算庫的實體地址偏移量。

以查詢 com.android.browse r的 libwebviewchromium.so 庫為例:

    #adb shell
    #ps|grep com.android.browser

    USER      PID   PPID  VSIZE    RSS     WCHAN      PC         NAME
    u0_a18    2571  1883  1423100  93768   ffffffff   b7668cdb S com.android.browser

    #cat /proc/2571/maps |grep libwebviewchromium.so
    8284f000-82942000 r--p 41391000 08:06 918        /system/lib/libwebviewchromium.so   

由此計算其指令在檔案內的偏移量:

    0x413afa96 - 0x41391000 = 0x1ea96        

然後用addr2line就可以檢視這條指令對應的原始碼在哪個檔案的哪個位置:

    $ arm-linux-androideabi-addr2line -e
    out/target/product/sp8825ea/symbols/system/lib/libwebviewchromium.so 0x1ea96    

可能遇到的問題以及建議

1、開啟DDMS後發現目標應用的程序資訊沒有顯示

    解決方案是:

    在註冊檔案的application標籤下開啟debuggable屬性:

    <application
        android:debuggable="true"

2、整個分析過程要保證ADB不會斷開連線;
3、抓取記憶體快照時DDMS的過程中不要最好不要操作裝置,否則可能很容易導致ANR。