- 移動App性能評測與優化
- TMQ專項測試團隊
- 1704字
- 2019-01-03 21:41:02
1.1 新手入門
當軟件實現了新功能后,準備發布版本前,往往需要進行一輪性能測試以確定沒有性能問題,這類測試通常包括功能的流暢度、電量消耗和內存使用情況等。
由于內存組成具有復雜性,實際上并沒有簡單通用的方法就能夠發現所有的內存問題。下面,我們會圍繞一組案例展開,通過對案例的分析講解各種內存測試的工具和方法。這些例子都是從真實的測試案例中提取的,經過加工后使得問題表現得更加明顯。
接下來我們從一個最常見的內存泄漏開始,作為最典型的內存問題,類似的情況可能在無數應用的無數版本中出現過,而且還會不斷地在新版本里出現。對于這樣的問題,我們必須要準確識別出來。
在大部分應用中,經常會有一類功能是需要加載附加資源的,比如顯示從網絡下載的文本或圖片。這類功能往往需要在內存中存放要使用的資源對象,退出該功能后,就需要將這些資源對象清空。如果忘了清理,或者是代碼原因造成的清理無效,就會形成內存泄漏(GC)。我們的測試任務就是保證功能的正常,并且不會有遺留的內存對象造成泄漏。
要開始進行性能測試,測試工具是必不可少的。我們一般都會優先使用SDK/IDE自帶的工具,因此首先會想到的工具就是和IDE集成在一起的Android Device Monitor/Android Studio了。
大多數情況下,功能代碼都是由Dalvik虛擬機里執行的Java代碼實現的,因此主要的內存消耗也是由Java代碼使用new分配的內存。Android Device Monitor和Android Studio能夠方便地觀察Heap Alloc部分的大小,進行初步的統計,還能夠觀察到GC發生時的內存變化情況,如圖1-1和圖1-2所示。

圖1-1 使用Android Device Monitor觀察應用的內存消耗

圖1-2 使用Android Studio觀察應用的內存消耗
在圖1-1中,我們能夠看到應用當前消耗了多少內存,以及各種不同類型對象的初步統計。在圖1-2中,Android Studio進一步將內存數據進行了圖形化,這樣就能方便地看出GC(垃圾回收)情況和明顯的內存趨勢。如果存在明顯的內存泄漏,那么在圖中就會表現為隨著功能的反復使用,內存值不斷升高,即使出現GC也沒法降下來,如圖1-3所示。

圖1-3 典型的內存泄漏
發現了內存泄漏,通常就可以交給開發去處理了。但我們并不只是給開發人員丟一個問題描述和復現路徑過去,而是利用手頭的工具,獲得一些更詳細的數據,能夠使大家更快地定位和解決問題,并對內存進行分析。這樣分析內存獲得詳細數據的首選工具就是Eclipse Memory Analyzer Tool(MAT)。
MAT是使用非常廣泛的Java內存分析工具,功能強大。已經有很多關于它的詳細教程,在本書中就不再細述用法。本節主要介紹使用MAT在分析Android應用時的一些常用技巧。
通常我們用MAT打開hprof文件后,能夠在首頁看到Top Consumers和Component Report等功能,使用這些功能能夠快速定位一些大塊的內存消耗。但對于Android應用的hprof文件,我們在使用了Top Consumers統計使用情況后,往往只能看到如圖1-4所示的情況。

圖1-4 使用MAT分析內存構成
系統的資源類占據了很大一部分的內存,而其余的前幾名也往往是系統類。這是由于從虛擬機角度不會區分系統框架和應用自身的對象,后面的1.4.3節會詳細說明出現這種現象的原因。
為了去除這部分對分析的干擾,我們在用Android SDK提供的hprof-conv轉換時需要增加一個參數:
hprof-conv [-z] <infile><outfile> -z: exclude non-app heaps, such as Zygote
另一種可替代的方法是使用OQL。如果hprof文件是已經轉換過的,可以在數據中尋找應用的Application類對象,將對象地址轉換為十進制后輸入以下查詢語句:
select * from instanceof java.lang.Object s where s.@objectAddress > 1107296256
使用-z參數轉換或OQL查詢后得到的對象集合就只包含應用代碼分配的部分了。在此基礎上使用MAT提供的Top Consumers和Component Report等功能就能夠得到比較準確的結果,如圖1-5所示,沒有了系統類所占內存的干擾,只有應用自身代碼創建的對象,對于發現內存問題比較有幫助。

圖1-5 分離之后再次分析內存構成
對于一般的內存泄漏類問題,使用以上方法后通過MAT提供的分析報告就很容易識別出來。在我們以往的測試經歷中,用這種方法發現了上百次的內存問題。這些內存往往是加載后忘了釋放的Bitmap,臨時生成的byte數組和文件緩沖區,包含Handler的Activity,等等。
接下來我們看一個真實的應用測試案例。在這個案例里,有些位圖在使用完之后由于種種原因,一直沒有銷毀而存在于ImageLoader里,使用一段時間后ImageLoader會變得越來越龐大。使用上面介紹的方法去除了系統的影響后,MAT的泄漏報告給出了結果,如圖1-6所示,ImageLoader消耗了接近1/3的內存。
有了這樣的數據,接下來就可以結合圖片追蹤代碼,看引用到ImageLoader的代碼部分哪里有問題,從而快速修復問題。

圖1-6 MAT識別出來的問題