案例:隱祕而低調的內存泄露(OOM)

內存泄露測試的整個過程以下:android

  • 在手機裏啓動被測APP並打開DDMS。ide

  • 在DDMS中選中【com.example.android.hcgallery】以後單擊按鈕【show heap updates】,而後切換到標籤頁【VM Heap】,再單擊按鈕【Cause GC】。測試

  • 不斷操做APP,並觀察Heap。通過一段時間的操做咱們發現不管是%Used仍是data object的Total Size都在不斷增長,如圖。正常狀況下Total Size會穩定在必定範圍內。spa

圖 VM Heap 1orm

  • 即便進行Cause GC以後仍會繼續增長,如圖對象

圖 VM Heap 2排序

  • 此時咱們懷疑若是長期下去可能有內存泄露的可能性,爲了進一步分析咱們單擊按鈕【Dump HPROF File】,獲得一個後綴爲hprof的文件(生成該文件的時間較長,請耐心等待)。內存

  • 使用命令hprof-conv將獲得的hprof文件轉化爲標準的hprof,這樣MAT才能識別。it

  • 使用MAT打開轉化以後的hprof文件,選擇圖中的【Leak Suspects Report】便可。以後你會看到一個概要信息,如圖。它只是給出一個宏觀的概念,告訴你某些問題的佔比,對於分析並無實質性的幫助。class


  • 單擊柱形圖標按鈕【Histogram】會生成一個視圖,它顯示的是類實例的列表,其中Shallow Heap表明對象自身佔用的內存大小,不包括它引用的對象。Retained Heap表明當前對象大小和當前對象可直接或間接引用到的對象的大小總和。

  • 在Shallow Heap列進行從大到小的排序,咱們發現byte[]佔比最大,選中以後右鍵依次選擇【List objects】>【with incoming referenes】進行鑽取,如圖。

圖 Histogram視圖

  • 再次按照Shallow Heap列進行從大到小的排序,選擇一個較大的對象並依次展開它的路徑,如圖。這裏咱們關注本身寫的代碼,也就是com.example.android.hcgallery.ContentFragment,咱們發現mBitmap比較可疑。這種方法適合對代碼比較熟悉的朋友。

圖 with incoming references

  • 除了上述方法以外你也能夠經過排除弱引用來分析,這樣能減小干擾因素。先按照Retained Heap從大到小排序,以後右鍵最大的,依次選擇【Path To GC Roots】>【exclude weak references】,獲得如圖的數據。發現sBitmapCache這個變量佔的比例較大,可能有問題。

圖 exclude weak references

小強課堂 在Java中存在強引用、弱引用、軟引用,這裏給你們作一個普及:

強引用:垃圾回收不會回收它,須要咱們主動設置爲null。

弱引用:顧名思義比較弱,當垃圾回收發現它只具備弱引用對象時,無論當前內存空間是什麼狀況,都會進行回收。

軟引用:若是它只具備軟引用對象時,內存空間足夠,垃圾回收器就不會回收。但若是內存空間不足了,就會回收。

  • 以後排查代碼發現sBitmapCache是static HashMap,mBitmap使用完成以後沒有recycle掉。

  • 最後修改代碼,在mBitmap != null時進行mBitmap.recycle()。


這樣一步步作下來至少你不會以爲混亂,而是有規可循。另外,有些內存泄露的分析可能無法一次性分析出來,須要屢次,這就考驗你們的耐心了。其實只要記住,分析要有規可循,耐心必不可少,任何難題均可以解決的。

相關文章
相關標籤/搜索