天天看點

Android記憶體分析工具:Memory Profiler

一、前言 

我們知道,Android系統檢測到app有不再使用對象時,就會進行記憶體回收相關的工作。

盡管Android檢測無用對象、回收記憶體的方法在不斷改進, 

但在目前所有的Android版本中,進行上述工作時,系統仍需要短暫地停止app的運作。

在大多數情況下,系統進行記憶體回收的行為是無法被使用者察覺到的。 

然而,如果應用配置設定記憶體的速度大于系統回收的速度, 

那麼app程序的正常運作可能就回受到影響。

畢竟,系統必須回收到足夠的供app需要的記憶體,才會恢複處于暫停狀态的app。 

在這種情況下,app就可能出現掉幀、卡頓等現象。

在更嚴重的情況下,如果出現了記憶體洩露的問題,那麼系統中就可能堆積無法釋放的記憶體, 

使得系統必須更加頻繁地進行記憶體回收,進而降低系統的性能。

甚至在極端條件下,系統不得不殺死部分正在背景運作的app程序。 

于是使用者将背景應用移到前台時,卻發現應用無故重新開機,這顯然帶來了較差的使用者體驗。

由此可見,記憶體對于app而言,是極其關鍵的性能名額。 

目前,分析app記憶體的工具有很多, 

本文主要記錄一下Android Studio内置的記憶體分析工具Memory Profiler。

二、基本介紹 

Memory Profiler是Android Profiler的一個元件, 用于幫助分析記憶體洩露和記憶體抖動的問題。 

當PC連接配接Android L以上的裝置時,該工具才能夠正常使用。

Memory Profiler的功能包括: 

展示應用記憶體使用情況的實時圖像、抓取記憶體的dump資訊、強制垃圾回收及追蹤記憶體配置設定。

2.1 開啟步驟 

打開Memory Profiler的步驟為: 

1、 依次點選Android Studio的View → Tool Windows → Android Profiler, 

或直接點選工具欄Android Profiler對應的圖示;

2、 PC連接配接Android終端後,在Android Profiler對應的區域選擇接的裝置和需要監控的程序: 

Android記憶體分析工具:Memory Profiler

3、 點選Android Profiler界面中MEMORY區域的任意位置,即可開啟Memory Profiler,如下圖所示: 

Android記憶體分析工具:Memory Profiler

需要注意的是,如果PC連接配接Android 7.1以下的裝置時,有些關鍵資料可能無法被Android Profiler統計, 

此時Android Profiler會顯示如下資訊: 

Android記憶體分析工具:Memory Profiler

這時我們需要依次點選Android Studio的Run → Edit Configurations → Profiling 按鍵,選中app後點選Enabled advanced profiling, 

如下圖所示: 

Android記憶體分析工具:Memory Profiler

為了支援該功能,要求app對應的gradle版本必須在2.4以上。

2.2 界面介紹 

打開Memory Profiler後,主界面如下所示(為了友善,這裡直接盜取Android技術文檔中的圖): 

Android記憶體分析工具:Memory Profiler

其中: 

标注1對應的按鍵用于強制記憶體回收。

标注2對應的按鍵用于抓取程序記憶體的dump資訊。

标注3對應的按鍵用于記錄記憶體的配置設定資訊(連接配接Android 7.1及以下才會有此按鍵)。 

初次點選時,對應統計的開始時間點;再次點選時,對應統計的結束時間點。 

程序在兩個時間點之間的記憶體配置設定資訊,将被Memory Profiler記錄和分析。

标注4對應的區域用于縮放時間軸。

标注5對應的按鍵用于顯示實時的記憶體資料。

标注6對應的區域用于記錄事件發生的時間點及大緻持續的時間(例如activity狀态改變、使用者操作界面等事件)。

标注7對應的區域用于顯示記憶體使用情況對應的時間軸(與标注6結合,就可以看出各事件帶來的記憶體變化情況)。 

需要說明的是,标注7對應區域顯示的内容包括: 

不同類型記憶體占用情況對應的圖像; 

配置設定對象數量對應的短畫線; 

記憶體回收事件發生的時機。

2.3 統計的資料類型及含義 

Memory Profiler主要根據Android系統提供的資訊, 

統計app獨自占用記憶體,即不統計app與系統或其它app共有的記憶體。

Memory Profiler統計記憶體的種類如下圖所示: 

Android記憶體分析工具:Memory Profiler

如上圖所示,其中: 

Java表示Java代碼或Kotlin代碼配置設定的記憶體;

Native表示C或C++代碼配置設定的記憶體(即使App沒有native層,調用framework代碼時,也有可能觸發配置設定native記憶體);

Graphics表示圖像相關緩存隊列占用的記憶體;

Stack表示native和java占用的棧記憶體;

Code表示代碼、資源檔案、庫檔案等占用的記憶體;

Others表示無法明确分類的記憶體;

Allocated表示Java或Kotlin配置設定對象的數量(Android8.0以下時,僅統計Memory Profiler啟動後,程序再配置設定的對象數量; 

8.0以上時,由于系統内置了統計工具,Memory Profiler可以得到整個app啟動後配置設定對象的數量)。

三、基本用法 

對Memory Profiler有了基本的了解後,我們來看看它的基本用法。

3.1 檢視記憶體配置設定情況 

Memory Profiler可以檢視兩個時間點之間的記憶體配置設定情況,包括: 

對象的類型、占用記憶體的大小、棧資訊等。 

連接配接8.0以上的裝置時,Memory Profiler還可以顯示對象被回收的時間。

PC連接配接8.0以上的裝置時,在記憶體統計的時間線上,直接點選和拖動就可以選擇觀察區域; 

連接配接低版本的裝置時,則需要點選Record Memory allocations按鍵(2.2小結介紹的标注3)選擇觀察區域。

標明觀察區域後, Memory Profiler就可以統計這段時間内app配置設定記憶體的情況: 

Android記憶體分析工具:Memory Profiler

從圖中可以看出,Memory Profiler可以顯示配置設定對象的類名; 

點選類後,會在Instance View顯示具體的對象; 

點選具體對象後,會在Call back區域顯示調用棧。 

點選調用棧資訊後,就會跳轉到具體的代碼。

3.2 檢視記憶體占用情況 

點選2.2小結介紹的标注2,即可抓取點選後一段時間内app占用記憶體的dump資訊。

通過dump資訊,我們可以看到app目前仍存在于記憶體中的對象。 

結合代碼,我們可以分析是否有本應被析構卻仍存活的洩露對象。

與統計記憶體配置設定資訊一樣,記憶體占用資訊同樣會顯示對象的類型、數量、占用記憶體的大小、引用關系等。 

如下圖所示: 

Android記憶體分析工具:Memory Profiler

圖中Alloc Count表示堆中配置設定對象的數量; 

Shallow Size表示對象使用Java記憶體的大小,機關為byte; 

Retained Size表示對象占用的實際記憶體大小,大于等于Shallow Size; 

7.0及以上版本的裝置,還會顯示對象占用的Native Size。

點選具體的對象時,也會顯示Instance View。 

此時,Instance View顯示的資訊變多了,包括: 

Depth表示目前對象到任一GC root的最短跳數; 

Shallow Size、Retained Size的含義與前文一緻。 

同樣,7.0及以上版本的裝置,還會顯示對象占用的Native Size。

從圖中可以看出,Instance View不會顯示棧資訊。 

如果想獲得棧資訊的話,必須先點選Record Memory allocations按鍵。

四、使用示例 

利用Memory Profiler,我分析了一下某反病毒引擎SDK的記憶體占用情況。 

随便寫了個demo,繼承SDK後啟動app,記憶體占用情況如下圖所示: 

Android記憶體分析工具:Memory Profiler

然後,通過操作UI初始化SDK,發現穩定後記憶體占用情況如下圖所示: 

Android記憶體分析工具:Memory Profiler

比對前後兩圖,不考慮界面UI變化消耗的記憶體, 

可以看出:記憶體增加的主體部分來自于Native函數,其它類型的記憶體變化幾乎可以忽略。 

這是因為該SDK初始化時,最主要的工作是在Native層加載底層的so檔案。

接下來,我們在demo裡調用SDK的接口,批量掃描樣本,統計記憶體消耗情況如下圖所示: 

Android記憶體分析工具:Memory Profiler

從圖中可以看出app消耗的記憶體飙升到了104M, 

與初始化後的記憶體相比,其中增加主要是code和native類型的記憶體。

根據2.3小結的描述,我們知道code類型統計的是app程序需要的資源檔案、庫檔案等, 

是以這部分記憶體主要是SDK中引擎加載病毒庫等消耗掉的記憶體; 

而Native記憶體的消耗,應該也是由于引擎掃描檔案導緻的。

按照3.1小結的描述,我們檢視了一下批量掃描這段時間内, 

app程序記憶體配置設定的情況,如下圖所示: 

Android記憶體分析工具:Memory Profiler

容易看出,在這段時間内,除去native記憶體外,整個app配置設定記憶體并不大, 

且按照對象占用記憶體的大小排序,排在前列的都是基本資料類型。 

是以,這段時間内app程序的記憶體應該是比較正常的。

我們進行GC操作,記憶體情況如下圖所示: 

Android記憶體分析工具:Memory Profiler

發現記憶體幾乎和掃描前一緻,按照3.2小結進行dump分析,沒有發現洩露對象。 

是以,可以确認SDK不存在記憶體洩露的問題(dump資訊含有sdk的隐私,這裡就不再附圖了)。

五、總結 

至此,我們已經介紹了Android Memory Profiler工具的基本情況, 

并簡單列舉了該工具的使用方式。

個人感覺,不同于LeakCanary, 

Android Memory Profiler更側重于宏觀場景下的記憶體分析。

版權聲明:轉載請注明:http://blog.csdn.net/gaugamela/article

繼續閱讀