效能評估與分析範例

以下範例說明如何搭配使用系統追蹤功能和 Macrobenchmark,並透過記憶剖析機制,評估和改善特定類型的效能問題。

使用 systrace 對應用程式的啟動進行偵錯

如要對啟動時間進行偵錯,推薦您使用 systrace 記錄。Systrace 是一個系統,它能利用預先編譯的程式碼來計算出特定事件發生所需的時間長度。這些追蹤記錄可讓您瞭解應用程式的運作情形,甚至是整個系統中的各個程序。Android 平台和 Jetpack 程式庫會對應用程式中眾多的重要事件進行檢測,系統中也會留下記錄。如要掌握應用程式的運作全貌,您也可以使用自訂追蹤記錄檢測應用程式。追蹤記錄會顯示在相同的 Systrace 視覺化工具中。

使用 systrace 或 Perfetto

如要進一步瞭解 systrace 基本使用方式,請觀看以下影片:應用程式偵錯效能

為分析啟動時間,您必須先瞭解啟動期間發生的狀況。除了本頁面提供的說明外,如需應用程式啟動程序的簡介,請參閱「應用程式啟動時間」一文。

應用程式啟動的各個階段如下:

  • 啟動程序
  • 初始化通用應用程式物件
  • 建立及初始化作業
  • 加載版面配置
  • 繪製第一個框架

啟動類型有下列幾個階段:

  • 冷啟動:當應用程式在啟動後首次啟動,或在遭使用者或系統終止程序後首次啟動,就會發生冷啟動。此時啟動作業會建立一個新程序,無暫存狀態
  • 暖啟動:應用程式已在背景執行,但必須重新建立作業並移至前景運作,就會進入這個階段。為重新建立作業,不是重複使用已存在的程序,就是利用暫存狀態重新建立程序。Macrobenchmark 測試程式庫可支援採用第一選項的持續性暖啟動測試。
  • 熱啟動:當程序和活動都仍在執行,只需移至前景、可能需視情況重新建立部分物件,並轉譯新前景活動時,就會發生熱啟動。這是最省時的啟動狀況。

我們建議使用「開發人員選項」中內建的裝置端系統追蹤應用程式,來擷取系統追蹤記錄。如要透過指令列工具,Perfetto 適用於 Android 10 (API 級別 29) 以上版本,而較舊版本的裝置則應使用 systrace

請注意,建立初始活動後,應用程式處理啟動程序的方式可能大不相同,因此「第一個影格」一詞有點不當。有些應用程式會持續加載多個框架,而有些甚至會立即展開次級作業。

在應用程式啟動完成之後,我們建議盡可能進行 reportFullyDrawn 呼叫 (適用於 Android 10 以上版本)。

針對這些系統追蹤記錄,您需要注意的地方包括:

監控系統衝突
圖1. 受監控保護的資源如果發生內部競爭,可能會造成應用程式的啟動作業大幅延遲。

同步綁定資料傳輸
圖2. 從應用程式的主要路徑中找出不必要的資料傳輸。

垃圾資訊即時收集作業
圖3.即時的垃圾資訊收集作業相當常見,對系統影響程度也相對較低。但如果經常發生,建議利用 Android Studio 記憶體分析器進行調查。

啟動期間的 I/O
圖4. 查看啟動期間的 I/O 狀況,並尋找較嚴重的停頓問題。

請注意如圖 4,如有其他程序同時執行 I/O 可能會造成衝突,因此請確保沒有其他程序同時在進行。

其他執行緒的重大作業會干擾 UI 執行緒,因此請留意啟動期間的背景作業。請注意,不同裝置的 CPU 設定可能有所不同,因此可同時執行的執行緒數量會因裝置而異。

另請參考指南:造成資源浪費的常見原因

使用 Android Studio 記憶體分析器

Android Studio 記憶體分析器具有強大的功能,可釋放記憶體被佔用或不當使用模式造成的記憶體壓力。可讓您即時查看物件配置與回收情況。

要修正應用程式的記憶體問題,您可以使用記憶體分析器來追蹤垃圾資訊收集進行的原因和頻率,以及是否可能發生記憶體流失,導致您的資訊量堆積過多。

剖析應用程式記憶體可細分為下列步驟:

1. 偵測記憶體問題

如要偵測記憶體問題,請先記錄應用程式的記憶體剖析工作階段。接著找出哪些物件的記憶體用量正在增加,並在最終觸發垃圾收集事件。

物件數量增加
圖5.記憶體分析器顯示,隨著時間進行,各處分布的物件數量持續增加。

垃圾資訊收集作業
圖6.記憶體分析器顯示垃圾收集事件。{.:image-caption}

一旦辨識出會增加記憶體壓力的物件後,請開始分析根本原因。

2. 診斷記憶體空間壓力熱點

選取時間軸範圍,以便視覺化呈現物件分布狀況和各物件占用的空間大小。

視覺化呈現物件分布狀況和各物件占用空間大小
圖7.記憶體分析器顯示在所選時間軸範圍內的配置和大小。

這些資料的分類方式有很多種。以下各節將以案例說明,如何用不同檢視方式來協助您分析問題。

依類別來編排

如要搜尋會產生物件的類別,依類別編排會是實用的做法。系統會從記憶體集區快取或重複使用這些類別。

舉例來說,假設您看到某個應用程式每秒可建立 2,000 個「Vertex」類別的物件。這會讓配置量每秒增加 2,000 個,您會在依類別排序時看到這種狀況。是否應該重複使用這類物件,以避免產生垃圾資訊?如果答案為「是」,可能會需要導入記憶池。

依呼叫堆疊來編排

當記憶體配置到熱路徑,例如位於迴圈內或有特定功能需配置多項工作,依呼叫堆疊編排會是實用做法。依呼叫堆疊來檢視,將可查看分配熱點。

淺層大小與保留大小

淺層大小只會追蹤物件本身占用的記憶體,因此最適合追蹤主要由原始物件組成的簡易類別。

保留大小會顯示以下兩者的總和:物件直接配置的記憶體,以及物件單獨參照的其他相關物件所配置的記憶體。由於需要考慮其他物件的占用量,而不單純只有原始空間欄位。在追蹤複雜物件造成的記憶體壓力時,參考保留大小較為適合。如要取得這個數值,請使用記憶體分析器建立記憶體傾印。曾經堆積的物件將會顯示出來。

完整記憶體傾印
圖8.您隨時可以在記憶體分析器工具列中,點選「Dump Java heap」按鈕來建立記憶體傾印。

以欄位格式新增
圖 9. 建立記憶體傾印時將顯示一欄位,呈現堆積部分的物件配置。

3. 測定最佳化的影響

垃圾資訊的收集狀況是一項易於評估的記憶體最佳化改善項目。當最佳化作業成功釋放記憶體壓力,您應該會看到次數較少的垃圾收集 (GC)。如要進行評估,請在分析器時間軸上測量垃圾資訊收集之間的間隔時間長度。記憶體最佳化過後,您應該會發現垃圾資訊收集之間的間隔時間較長。

這些記憶體改善項目的最終影響如下:

  • 只要應用程式並非持續受到記憶體壓力,就較不會因記憶體空間不足而遭到系統終止。
  • 減少垃圾資訊收集的次數可以改善資源浪費的相關指標。這是因為垃圾收集事件會造成 CPU 爭用情形,導致轉譯工作在垃圾收集期間遭到延遲。