Memory Profiler是Android Profiler中的一個組件,Android Profiler是Android3.0用來替換之前Android Monitor的觀察工具,主要用來觀察內存、網絡、cpu溫度。
Memory Profiler它能夠讓你識別出來內存泄露和內存抖動,導致應用卡頓,anr和crash,他可以給你展示一個內存使用的真實圖表,讓你知道當時內存使用情況,還能強制內存回收,和跟蹤內存分配
打開方式
為什么去觀察應用內存使用情況
Memory Profiler是用來解決內存分配中產生抖動,導致應用卡頓、anr和crash問題,在Android系統內存管理上,它是提供一套內存回收機制去回收無用的對象,
其實就是Dalvik虛擬機的垃圾回收器,當垃圾回收器啟動回收機制的時候,其實會對應用的運行產生一點影響,但是這種影響來說一般是微乎其微的,覺察不到,但是如果你的內存分配比垃圾回收快很多,這種情況可能導致垃圾回收器回收內存不及時,從而導致應用出現卡頓的現象(其實是內存抖動所產生的影響),另外一個問題是內存泄露,內存的持續泄露可能導致內存溢出,從而app運行出現oom異常
Memory Profiler通過以下方面防止上面出現的問題:
1.觀察不必要的內存分配(這種內存分配導致效率降低)
2.Dump the java heap去觀察指定時間對象在內存中的分配情況,若干次Dump能夠幫助你發現內存泄露
3.測試極端的用戶交互情況下的內存分配(比如狂點某個請求按鈕),看看內存使用情況如何,是否出現內存抖動
1:強制內存回收
2:Dump the java heap
3:開始/停止記錄內存分配情況
4:放大/縮小時間線
5:實時播放內存分配情況
6:發生一些事件的記錄(如Activity跳轉,事件的輸入、屏幕的旋轉)
7:使用的內存時間線
關於頂部的幾種內存類型介紹
Java:java代碼分配的內存
Native:c/c++代碼分配的內存(有時候其實並沒有使用c/c++代碼,但還是會有Native的內存分配,因為Android Framework會去通過java代碼訪問一些需要使用Native的資源,如圖像資源的Bitmap)
Graphics:圖像緩存等,包括GL surfaces,GL textures等
Stack:棧內存(包括java和c/c++)
Code:代碼的內存分配(例如代碼,資源,libs等等)
Other:這個是系統都不知道什么類型的內存
Allocated:java分配的對象個數
如何觀察對象分配情況
查看內存分配情況,也就是我們前面提到需要關注什么類型的對象被分配,分配了多大空間
1.在Class Name列看一下有沒有異常分配的對象,個數很多,占用內存比較大,點擊頭部Class Name進行一個按字母排序操作,點擊Class Name面板下面的類名可以看到instance View面板的詳細對象信息
2.點擊Instance View面板上的對象,可以看到調用棧信息和調用的線程
3.在Call Stack中點擊可以跳轉到實際的代碼
以上是捕獲一段時間的內存分配情況,如果想捕獲一瞬間的內存分布需要用到heap dump
捕獲一個heap dump
捕獲一個heap dump觀察某一個時間點的對象分配情況,注意之前介紹的是一個時間段,而這里是時間點。它有助於幫助我們分析內存泄露,比如當我們使用一段時間后
捕獲了一個heap dump這個heap dump里面發現了並不應該存在的內存對象,這說明存在內存泄露了,通過一個 heap dump你可以看到以下內容
1.你的app分配了什么樣的對象類型,每個類型分配了多少個和大小
2.使用了多少內存
3.每個對象在代碼中的使用位置
4.對象分配的調用棧情況
捕獲一個heap dump在工具欄中點擊之前面板介紹中的按鈕2,稍等一會變能夠看到類似於之前內存分配的面板彈出
在圖片中可以看到如下列
Class Name:類名
Alloc Count:對象個數
Native Size:c/c++層內存大小(byte)
Shallow Size:java層內存大小(bytes)
Retained Size:這個是這個類中所引用到的對象的總大小*該類對象的個數
當點擊app heap下拉列表會出現3個選項
Defaule heap:
App heap:app中的堆內存
Zygote heap:這個按照官方的解釋是來自安卓系統fork進程的地方產生的寫數據備份
當點擊Arrange by class下拉列表會出現3個選項
Arrange by class:根據類名進行分組
Arrange by package:根據包名進行分組
Arrange by callstack:根據調用棧進行分配(這個目前也不是太理解)
當我們點擊其中一個類的時候會彈出一個新的instance View面板,如下圖:
分析heap,按照以下步驟:
1.瀏覽Class Name列表,看看有沒有大量的對象存在,並且這些對象你認為是不應該存在的,可能存在內存泄露的情況,點擊類名可以看到詳細的對象信息
2.在這個Instance View面板中,點擊一個實例References面板就會顯示出來,里面都是使用該Instance的Reference,點擊箭頭可以看到引用它的所有區域,點擊鼠標右鍵可以選擇 go to instance去看到引用該引用的引用,或者jump to source去看調用的源代碼
另外heap dump也是可以保存成為HPROF文件的,點擊如下按鈕可保存起來,用於以后分析,或用其他工具分析
一般出現內存泄露的原因有:
1.長期引用到Activity,Context,View,Drawable的對象
2.非靜態內部類,例如Runnable她可以引用到Activity的實例
3,一些長期的緩存
具體分析一下 如何使用Memory Profiler查找內存泄露
查找內存泄露有以下幾個方式
1.一般排查內存泄露的方式是,啟動應用,看一下當前內存使用多少,使用應用一段時間后,退回到應用首頁,看看當前內存又是多少,進行一次heap dump看看結果,分析一下有沒有可疑對象分配(比如說大量重復的Activity,同一類型的對象比較多,對象內存占用較大)
2.發現可疑點后,通過分析結果,可疑找到相應代碼,找到代碼當然也能找到使用代碼的場景,例如Activity泄露,返回進行畫面跳轉(如果你的應用支持橫豎屏切換的話,也可以反復旋轉屏幕),然后強制gc回收,看看內存是否存在只增不減的情況
3.也可以使用allocation跟蹤一段時間內存分配情況,拿出來分析
4.最后推薦一款leakcanary工具使用(具體可看https://github.com/square/leakcanary)
正式例子
啟動一個類似內存泄露的app,然后跑一段時間,進行了一次heap dump,結果如下
很明顯發現一個可疑的類OutOfMemActivity,它存在多個實例,實際上在已知該app業務邏輯中是不應該會有這么多OutOfMemActivity實例的,於是點開他的Instance View
可疑點如紅色箭頭所指,因為外部類實例引用到Activity都是不正常的操作,這里Broadvast的實例引用到了Activity
點擊跳轉到源碼,發現是內部類引用到外部類實例(Activity)的情況導致內存泄露