1. 程式人生 > >記憶體優化排查

記憶體優化排查

一、摘要

該部分屬於進階內容,要先掌握了java記憶體回收機制,說白了就是引用計數法和可達性分析法。但是程式碼寫的再認真,也難免出現一兩個差錯。這一兩個差錯就會導致記憶體洩漏,輕則記憶體增大,重則記憶體溢位。

二、背景

自從引入了WebView,記憶體變得難以測試,因為WebView記憶體不可控,一載入就導致記憶體暴漲,所以最近比較少跑記憶體測試了。直至在jara系統上反饋了專案出現記憶體crash,沒辦法,必須得處理了。

現象,記憶體達到了300m。

三、推廣建議

理解原理再深,也無法徹底避免問題的處理。就算了經過多次程式碼審查,也難以發現細節上的錯誤,還是要通過測試驗證,反覆排查,才能完成避免問題的出現。

大部分人都喜歡宣告成員變數,內部類。因為他們的作用域比較廣,程式碼寫起來比較爽。但是違反了“最小作用域原則”。往往就會導致記憶體洩漏。

最終,專案經過優化,記憶體減少到72M

四、正文

問題復現:跑monkey測試,在過程中執行:adb shell dumpsys meminfo 包名。就算可以輸出應用的記憶體資訊。多次執行就可以輸出記憶體曲線圖,檢視記憶體情況。

排除干擾:在一次競品分析中,發現小米使用者中心,把WebView都放在一個獨立的程序,這樣就可以排除干擾了,也可以使apk輕量化。

重要步驟:

1、 手動排除問題,進入一個頁面前,執行adb shell dumpsys meminfo 包名。檢視記憶體,進入後再退出頁面,再次執行:adb shell dumpsys meminfo 包名。對比兩次的記憶體情況是否一致。如果出現記憶體異常,重複操作多次,確認那個頁面異常了。

記憶體資訊圖

說明:主要關注一下引數:

  •     Native Head:Native記憶體
  •     DalvikHead:虛擬機器記憶體
  •     EGL/GL:影象渲染相關。(activity洩漏時,該項會很大)
  •     Views/AppContexts/Activvities:例項,需要重點關注這三個引數

2、進一步排查

   基本上,經過上一步的操作,百分之九十的記憶體問題都會發現並且解決。還有比較難復現的情況,需要在monkey情況下復現。

排查方法:mat

方法:打一個debug版本的apk,跑monkey。跑完後退出頁面,執行:

adb shell am dumpheap 包名 /data/local/tmp/test.hprof

adb pull /data/local/tmp/test.hprof

hprof-conv test.hprof temp1.hprof

使用mat開啟temp1.hprof

檢視那些物件佔有大,排查程式碼

重要,點選QQL,執行查詢方法。

常用:

select* from instanceof android.graphics.Bitmap

select* from instanceof android.app.Activity 

select* from instanceof android.support.v4.app.Fragment

查詢出那些比較可能洩漏的例項。

因為dump前頁面已經退出了,所以存在的例項基本都是洩漏。都要處理。

洩漏點排查。右鍵物件,with all reference。查詢有那些物件長期引用它,導致它無法釋放。

常見案例:

  1.  xxxListener:如果你的物件實現了xxxListener方法,或者存在xxxListener的內部類,一定要注意反登出。(onClickListener會自己銷燬的)

  2.  所有Context,fragment被作為成員變數,引數的地方,都要考慮是否會長時間引用。(mvp中會)

  3.  廣播的註冊與登出

  4.  Bitmap要及時回收,Bitmap屬於大物件,會直接存在於老年代,最好是不用就回收,減少記憶體

  5. EventBus反登出