記憶體分析器是 Android Profiler 中的一個元件,可幫助開發者識别可能會導緻應用卡頓、當機甚至崩潰的記憶體洩漏和記憶體抖動。它顯示一個應用記憶體使用量的實時圖表,讓開發者可以捕獲堆轉儲、強制執行垃圾回收以及跟蹤記憶體配置設定。
打開記憶體分析器的步驟如下:
- 依次點選 View > Tool Windows > Profiler(也可以點選工具欄中的 Profile 圖示 )。
- 從 Android Profiler 工具欄中選擇要分析的裝置和應用程序,如果您已認證 USB 連接配接裝置但系統未列出該裝置,請確定您已啟用 USB 調試。
- 點選 MEMORY 時間軸上的任意位置以打開記憶體分析器
1 記憶體分析器概覽
當首次打開記憶體分析器時,可以看到一條表示應用記憶體使用量的詳細時間軸,并可使用各種工具強制執行垃圾回收、捕獲堆轉儲以及記錄記憶體配置設定。
如上圖所示,記憶體分析器的預設視圖包括以下各項:
- 用于強制執行垃圾回收事件的按鈕。
- 用于捕獲堆轉儲的按鈕。隻有在連接配接到搭載 Android 7.1(API 級别 25)或更低版本的裝置時,系統才會在堆轉儲按鈕右側顯示用于記錄記憶體配置設定情況的按鈕。
- 用于指定性能分析器多久捕獲一次記憶體配置設定的下拉菜單。選擇适當的選項可幫助開發者在進行性能剖析時提高應用性能。
- 用于縮放時間軸的按鈕。
- 用于跳轉到實時記憶體資料的按鈕。
- 事件時間軸,顯示活動狀态、使用者輸入事件和螢幕旋轉事件。
- 記憶體使用量時間軸,它會顯示以下内容:
一個堆疊圖表,顯示每個記憶體類别目前使用多少記憶體,如左側的 y 軸以及頂部的彩色鍵所示。
一條虛線,表示配置設定的對象數,如右側的 y 軸所示。
每個垃圾回收事件的圖示。
在 Android 8.0 及更高版本上,系統會一律為可調試的應用啟用進階性能剖析,如果使用的是搭載 Android 7.1 或更低版本的裝置,并非所有分析資料在預設情況下都可見。
2 記憶體計算方式
- Java:從 Java 或 Kotlin 代碼配置設定的對象的記憶體。
- Native:從 C 或 C++ 代碼配置設定的對象的記憶體。
- 即使應用中不使用 C++,也可能會看到此處使用了一些原生記憶體,因為即使您編寫的代碼采用 Java 或 Kotlin 語言,Android 架構仍使用原生記憶體代表您處理各種任務,如處理圖像資源和其他圖形。
- Graphics:圖形緩沖區隊列為向螢幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的記憶體。(請注意,這是與 CPU 共享的記憶體,不是 GPU 專用記憶體。)
- Stack:應用中的原生堆棧和 Java 堆棧使用的記憶體。這通常與應用運作多少線程有關。
- Code:應用用于處理代碼和資源(如 dex 位元組碼、經過優化或編譯的 dex 代碼、.so 庫和字型)的記憶體。
- Others:應用使用的系統不确定如何分類的記憶體。
- Allocated:應用配置設定的 Java/Kotlin 對象數。此數字沒有計入 C 或 C++ 中配置設定的對象。
3 檢視記憶體配置設定情況
記憶體配置設定情況圖表顯示記憶體中每個 Java 對象和 JNI 引用的配置設定方式:
- 配置設定了哪些類型的對象以及它們使用多少空間。
- 每個配置設定的堆棧軌迹,包括在哪個線程中。
- 對象在何時被取消配置設定(僅當使用搭載 Android 8.0 或更高版本的裝置時)。
如需錄制 Java 和 Kotlin 配置設定情況,可以選擇 Record Java / Kotlin allocations,然後選擇 Record。
如果裝置搭載的是 Android 8 或更高版本,則記憶體分析器界面将轉換為顯示正在進行錄制的單獨螢幕。可以與錄制上方的迷你時間軸進行互動(例如,更改選擇範圍)。如需完成錄制,選擇 Stop 圖示
4 如需檢查配置設定記錄,請按以下步驟操作:
浏覽清單以查找堆計數異常大且可能存在洩漏的對象。為幫助查找已知類,點選 Class Name 列标題以按字母順序排序。然後,點選一個類名稱。此時右側将出現 Instance View 窗格,顯示該類的每個執行個體。
在 Instance View 窗格中,點選一個執行個體。此時下方将出現 Call Stack 标簽頁,顯示該執行個體被配置設定到何處以及在哪個線程中。
在 Call Stack 标簽頁中,右鍵點選任意行并選擇 Jump to Source,以在編輯器中打開該代碼。
5 捕獲堆轉儲
堆轉儲顯示在捕獲堆轉儲時 對應的應用中哪些對象正在使用記憶體。特别是在長時間的使用者會話後,堆轉儲會顯示不應再位于記憶體中卻仍在記憶體中的對象,進而識别記憶體洩漏,捕獲堆轉儲後,可以檢視以下資訊:
- 應用配置設定了哪些類型的對象,以及每種對象有多少。
- 每個對象目前使用多少記憶體
- 在代碼中的什麼位置保持着對每個對象的引用
- 對象所配置設定到的調用堆棧
點選 Capture heap dump,然後選擇 Record,在轉儲堆期間,Java 記憶體量可能會暫時增加,這是很正常的現象,因為堆轉儲與對應的應用發生在同一程序中,并需要一些記憶體以收集資料。
在類清單中,可以檢視以下資訊
- Allocations:堆中的配置設定數。
- Native Size:此對象類型使用的原生記憶體總量(以位元組為機關)。隻有在使用 Android 7.0 及更高版本時,才會看到此列。
- 您會在此處看到采用 Java 配置設定的某些對象的記憶體,因為 Android 對某些架構類(如 Bitmap)使用原生記憶體。
- Shallow Size:此對象類型使用的 Java 記憶體總量(以位元組為機關)。
- Retained Size:為此類的所有執行個體而保留的記憶體總大小(以位元組為機關)。
從左側的菜單中,選擇需檢查的堆:
- default heap:當系統未指定堆時。
- app heap:您的應用在其中配置設定記憶體的主堆。
- image heap:系統啟動映像,包含啟動期間預加載的類。此處的配置設定確定絕不會移動或消失。
- zygote heap:寫時複制堆,其中的應用程序是從 Android 系統中派生的。
從右側的菜單中,選擇如何安排配置設定:
- Arrange by class:根據類名稱對所有配置設定進行分組。這是預設值。
- Arrange by package:根據軟體包名稱對所有配置設定進行分組。
- Arrange by callstack:将所有配置設定分組到其對應的調用堆棧。隻有在記錄配置設定期間捕獲堆轉儲時,此選項才有效。即便如此,堆中也很可能有在您開始記錄之前配置設定的對象,是以會先顯示這些配置設定,直接按類名稱列出它們。
點選一個類名稱可在右側打開 Instance View 視窗(如下圖 所示)。列出的每個執行個體都包含以下資訊:
- Depth:從任意 GC 根到標明執行個體的最短跳數。
- Native Size:原生記憶體中此執行個體的大小。 隻有在使用 Android 7.0 及更高版本時,才會看到此列。
- Shallow Size:Java 記憶體中此執行個體的大小。
- Retained Size:此執行個體所支配記憶體的大小
6 記憶體分析器中的洩漏檢測
在記憶體分析器中分析堆轉儲時,可以過濾 Android Studio 認為可能表明應用中的 Activity 和 Fragment 執行個體存在記憶體洩漏的分析資料。
過濾器顯示的資料類型包括:(需要 首先需要 捕獲堆轉儲)
- 已銷毀但仍被引用的 Activity 執行個體。
- 沒有有效的 FragmentManager 但仍被引用的 Fragment 執行個體。
在某些情況(如以下情況)下,過濾器可能會産生誤報:
- 已建立 Fragment,但尚未使用它。
- 正在緩存 Fragment,但它不是 FragmentTransaction 的一部分。