Eclipse-mat

Eclipse MAT -- android 內(nèi)存分析工具

資料

介紹

目前產(chǎn)品中,一直存在內(nèi)存溢出,頻繁崩潰的現(xiàn)象,作為一個門外漢,也需要了解下android 具體的測試方法以及優(yōu)化策略.
在搜索了許多問題之后,我們把問題定位到內(nèi)存溢出. 那么如何監(jiān)控移動設(shè)備(android)的內(nèi)存使用情況呢? 
經(jīng)過對比,MAT 在我們場景中已經(jīng)可以作為分析內(nèi)存的工具來使用.

Eclipse MAT

android studio 自帶了android device monitor ,可以提供錄制的hprof文件,并且拖拉到studio 中就可以進行簡單的分析,but .
看不懂~~ 回過頭來 ,還是使用eclipse-mat 來分析內(nèi)存吧 ,畢竟這個資料會多一些.
studio 錄制的 hprof 文件,需要通過SDK 自帶的hprof-conv 進行轉(zhuǎn)換之后才可以導(dǎo)入到eclipse-mat 
導(dǎo)入進來之后就需要對eclipse mat 的簡單使用有一個初步的了解.

名詞解釋

  1. Shallow heap : 對象自身占用的內(nèi)存
  2. Retained heap: 對象自身占用的內(nèi)存 + 對象直接或間接引用占用的內(nèi)存
  3. outgoing : 被引用
  4. ingoing: 引用
  5. weak reference: 弱引用 ,簡單描述為: 假如一個A 對象依賴一個弱引用的B對象,則,如果A 對象為null ,GC回收時候就會回收A
  6. soft reference: 軟引用,如果內(nèi)存足夠就不回收,如果不夠就回收,不回收時候該對象可以被程序使用.
  7. phantom reference: 虛引用, 無論從哪里都無法訪問虛引用所引用的對象,GC時候,直接就finalize,該對象清除時才加入到Reference隊列.
  8. GC root: 生成一個到gc 根 的引用關(guān)系
  9. dominator tree: 支配樹
  10. heap size: 堆大小,當(dāng)前空間不足則系統(tǒng)會自動增加大小
  11. Allocated: 堆中已分配大小,即app實際占用內(nèi)存大小,資源回收后,該值會變小.

內(nèi)存分析流程

    在android 平臺,長期占用一些資源的引用,造成內(nèi)存不能釋放,帶來的問題有很多,
    1. Drawable 由于加載Bitmap 導(dǎo)致的問題 ,比如旋轉(zhuǎn)屏幕會銷毀當(dāng)前activity,并創(chuàng)建一個新的activity.
                這時候則會重新加載UI視圖和資源.
    2. bitmap 圖片過大導(dǎo)致內(nèi)存溢出,編碼上需要options來減小圖片
    3. Handler 導(dǎo)致的內(nèi)存溢出.
    4. AsyncTask 由于非靜態(tài)匿名內(nèi)部類導(dǎo)致的內(nèi)存溢出
    5. Context 上下文的長時間引用導(dǎo)致的內(nèi)存溢出,如果需要緩存context 則需要使用applicationContext代替.
    
導(dǎo)致內(nèi)存溢出,也就是內(nèi)存中存在的引用關(guān)系得不到清理所導(dǎo)致的,所以,以后在開發(fā)過程中要考慮好對象的應(yīng)用.
那么配合mat 如何才能找出問題呢?


如何判斷內(nèi)存溢出風(fēng)險?

    在開啟 android device monitor 之后, 我們監(jiān)控 heap size , allocated 的大小變化,
通過觀察,發(fā)現(xiàn)沒問的應(yīng)用在幾個Activity 切換之后,內(nèi)存有最初的15M 維持到25-40 之間
設(shè)想,是否存在有些對象沒有釋放,導(dǎo)致內(nèi)存一直增加不降低呢? 
    通過導(dǎo)出的hprof 文件,我們 看看eclipse-mat 中又有哪些記錄呢?
    導(dǎo)入之后,我們發(fā)現(xiàn)mat 已經(jīng)發(fā)現(xiàn)了可能產(chǎn)生的問題 Leak Suspects ,當(dāng)然這是mat 懷疑的,
是否真的有問題,我們需要查看下GC root 依賴關(guān)系.
    Problem 1: Bitmap 的實例 占用了太多的引用. byte[]的積累已經(jīng)占用了16%.原因是內(nèi)存中 byte[] (可能)導(dǎo)致了問題.
我們通過histogram 發(fā)現(xiàn)排第一的就是byte ,查找下他的引用有哪些(使用list Object) 發(fā)現(xiàn)了被很多個實體引用.
通過sort 我們找?guī)讉€來看看問題,選中一個最大的(Path to GC Roots 去除掉弱引用和軟引用),這里出現(xiàn)了一個引用ROOT樹, 
找到有一個GuideRedActivity. 那么接下來查看下這個類,為什么一直在內(nèi)存中. 這個Activity 負責(zé)生成一個圖片遮罩效果.
    images.setBackgroundResource(xx);
通過一個點擊事件頻繁調(diào)用了 4次 setbackGroundResource,圖片大小為640*1200 ,通過分析,這里使用setbackgroundResource 確實
存在內(nèi)存泄漏的風(fēng)險.
    Problem 2: 40 byte[] 實例占用了大量的內(nèi)存12% . 這個問題和上面的Bitmap 問題應(yīng)該一直,那么我們再來分析一個. 我們通過
以上步驟找到第二個占用內(nèi)存比較大的byte[] ,查詢他的引用,好了,這個是應(yīng)用首頁,所有可能出現(xiàn)的地方比較多,隨便找一個看看
    webView.loadUrl(xx)
這是一個webview 頁面,這個加載了資源為什么也沒有釋放呢? 
查找原因 [webview oom](https://my.oschina.net/zhibuji/blog/100580) 

    Problem 3: 62個ImageView實例 占用的內(nèi)存太大.為什么ImageView 沒有銷毀呢? 并且還這么大呢? 通過跟蹤發(fā)現(xiàn),ImageView有些屬于
啟動之后就依賴的,所以導(dǎo)致他不會消失,特別是如果ImageView 每次都加載圖片, 這個時候就(有可能)導(dǎo)致內(nèi)存占用比較大,并且不銷毀的情況.

內(nèi)存解決方案

程序本身存在內(nèi)存溢出的風(fēng)險,那么,如何才能管控呢?
Bitmap一定要特別注意.如果使用之后,可以調(diào)用recycle 進行回收.bitmap = null 使其變成虛引用,加快GC回收
關(guān)于contenxt 的引用,盡量避免你使用.使用applicationContext 代替,比如 toast ,View 中都要注意避免使用contenxt,
最好全局中static 一個applicationcontext對象方便非Activity使用.
盡量避免使用非靜態(tài)的匿名內(nèi)部類.如果是線程則最好維護一個整個應(yīng)用的線程池.

開發(fā)建議

開發(fā)人員可以通過 leakcanary 來運行debug測試內(nèi)存溢出問題.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容