Android記憶體分析和調優(下)

yangxi_001發表於2013-12-05

最後一部分是關於native heap,.dex,/dev/other的優化。

Native Heap分析和優化

android的DDMS可以幫助檢視c++ native heap的使用,但需要一定的配置,而且必須是root的手機。

  1. 在~/.android/ddms.cfg增加"native=true"。這樣子ddms才會有native heap的tab。
  2. 指向下面adb命令開啟malloc的debug模式
    adb root
    adb shell setprop libc.debug.malloc 1
    adb shell stop
    adb shell start
  3. 開啟standalone的DDMS(不是eclipse中那個,是獨立的應用程式,sdk目錄下有),然後在native heap這個tab下,可以檢視native heap的分配情況。

      在很多手機上,即使執行了這些命令,還是看不到結果。原因是很多手機上並沒有安裝debug版本的malloc庫(包括libc_malloc_debug_leak.so 和 libc_malloc_debug_qemu.so)。這篇經常被引用的文章介紹了一種方法。是從供大家刷機用的CyanogenMod image中提取這兩個檔案,然後拷貝到自己的機器上。可以參考那片文章的具體步驟。

      下面的問題是隻能看到地址而不知道檔名和行號。至少有下面一些辦法

  1. 使用ndk中的arm-linux-androideabi-gdb(android ndk的gdb)來開啟.so檔案。這裡的.so不能使apk中使用的,因為那個已經把symbol給strip了。而應該使用 ***\obj\local\armeabi\***.so,這個是帶著symbol的。
    然後可以在gdb中使用info symbol 0x000xxxxx來定位到地址對應的函式名。這裡的0x000xxxxx是ddms中地址把前三位變成0。因為gdb .so中使用.so的靜態地址,而ddms中的地址經過動態連結,是記憶體的虛擬地址。但動態連結並不改變地址的後五位,所以這裡後五位保持不變,前三位變成0,從而轉換為so的靜態地址。
    然後用info line xxx.cpp:xxx來定位具體行。
    這個方法比較繁瑣,因為當時自己沒找到好辦法,就這麼用的。
  2. 用ndk的arm-linux-androideabi-addr2line。後面跟so和0x000xxxxx。跟gdb差不多,會簡單一些。
  3. 有人說設定PATH加上包含addr2line的目錄,然後再設定ANDROID_PRODUCT_OUT可以在ddms中直接顯示函式名和行號,但沒有試過。

/other/dev分析和優化

自己用的是4.2版本的android。每次開啟preference setting,/other/dev的private dirty都會增加很多(10M作用),並且不會釋放。通過檢視smaps,發現是/dev/pvrsrvkm導致的(4.3後裝置名改為kgsl-3d0)。這個是顯示相關的裝置,按我的理解,大概是視訊記憶體(如果沒有獨立視訊記憶體,那是用於顯示的記憶體)。通過網上查詢,並不是只有我遇到這個問題。例如chrome也有這個問題。但還是不知道為何這個會增加。在一通亂試後,發現如果對activity設定android:hardwareAccelerated=false,就能解決。此時只增加shared dirty,並且關掉activity,記憶體會被釋放。後來再查,看到stackoverflow上這篇文章,才知道這是4.2的一個bug。4.3和4.1都沒有問題。

.Dex mmaps優化

這個是java程式碼編譯只會的.dex檔案的大小。

開始自己使用eclipse編譯出來的apk作效能分析,發現這個也有幾M。但release版本的卻不到1M。轉念一想,原來是proguard的作用。proguard是android自帶的混淆器,會對java的類名,函式名,變數名等重新命名,給一個非常短的名字。有兩個作用,一個是使得反編譯的程式碼不容易理解,另一個就是減少了dex檔案的大小。經過這次記憶體分析,才發現其效果還是非常明顯的。

因為proguard無法對res下的layout,xml檔案做混淆,所以他們引用到的java類(例如一些view類)的名字是不能被改變的。所以一個小經驗是讓xml檔案儘量少的引用java類,從而提高混淆的比例。

總結

關於android記憶體優化,自己就先做了這些。整體思路就是從巨集觀到微觀,利用各種工具和網路資料,從記憶體佔用量最多的模組下手,一步步的分析原因,解決問題。再細化下去,還有很多程式碼級別的優化,例如perf tips裡介紹了很多經驗,memory efficient java也很值得參考。有時間再在這個級別做更多的優化。

相關文章