案例:隱秘而低調的記憶體洩露(OOM)

testingbang發表於2019-08-28

本文選自《大話軟體測試》一書


記憶體洩露測試的整個過程如下:

l 在手機裡啟動被測APP並開啟DDMS。

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

l 不斷操作APP,並觀察Heap。經過一段時間的操作我們發現不論是%Used還是data object的Total Size都在不斷增加,如圖。正常情況下Total Size會穩定在一定範圍內。

圖 VM Heap 1

l 即使進行Cause GC之後仍會繼續增加,如圖

圖 VM Heap 2

l 此時我們懷疑如果長期下去可能有記憶體洩露的可能性,為了進一步分析我們單擊按鈕【Dump HPROF File】,得到一個字尾為hprof的檔案(生成該檔案的時間較長,請耐心等待)。

l 使用命令hprof-conv將得到的hprof檔案轉化為標準的hprof,這樣MAT才能識別。

l 使用MAT開啟轉化之後的hprof檔案,選擇圖中的【Leak Suspects Report】即可。之後你會看到一個概要資訊,如圖。它只是給出一個宏觀的概念,告訴你某些問題的佔比,對於分析並沒有實質性的幫助。

圖 Leak Suspects Report

圖 概要資訊

l 單擊柱形圖示按鈕【Histogram】會生成一個檢視,它顯示的是類例項的列表,其中Shallow Heap代表物件自身佔用的記憶體大小,不包括它引用的物件。Retained Heap代表當前物件大小和當前物件可直接或間接引用到的物件的大小總和。

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

圖 Histogram檢視

l 再次按照Shallow Heap列進行從大到小的排序,選擇一個較大的物件並依次展開它的路徑,如圖。這裡我們關注自己寫的程式碼,也就是com.example.android.hcgallery.ContentFragment,我們發現mBitmap比較可疑。這種方法適合對程式碼比較熟悉的朋友。

圖 with incoming references

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

圖 exclude weak references

小強課堂 在Java中存在強引用、弱引用、軟引用,這裡給大家做一個普及:

強引用:垃圾回收不會回收它,需要我們主動設定為null。

弱引用:顧名思義比較弱,當垃圾回收發現它只具有弱引用物件時,不管當前記憶體空間是什麼情況,都會進行回收。

軟引用:如果它只具有軟引用物件時,記憶體空間足夠,垃圾回收器就不會回收。但如果記憶體空間不足了,就會回收。

l 之後排查程式碼發現sBitmapCache是static HashMap,mBitmap使用完成之後沒有recycle掉。

l 最後修改程式碼,在mBitmap != null時進行mBitmap.recycle()。

這樣一步步做下來至少你不會覺得混亂,而是有規可循。另外,有些記憶體洩露的分析可能沒法一次性分析出來,需要多次,這就考驗大家的耐心了。其實只要記住,分析要有規可循,耐心必不可少,任何難題都可以解決的。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69942496/viewspace-2655252/,如需轉載,請註明出處,否則將追究法律責任。

相關文章