評估應用程式效能總覽

此文件可協助您找出並修正應用程式的主要效能問題。

主要效能問題

許多問題都可能導致應用程式效能低落,以下列舉幾種應用程式中應注意的常見問題:

啟動延遲

啟動延遲時間是從輕觸應用程式圖示、通知或其他進入點開始,直到使用者資料顯示在畫面上所需的時間。

請在應用程式中確立下列啟動目標:

  • 在 500 毫秒內完成冷啟動。如果系統記憶體中沒有啟動應用程式的記錄,就會出現「冷啟動」。這是應用程式自重新啟動,或使用者/系統終止應用程式的程序後,首次啟動時會出現的情形。

    相反地,如果應用程式已在背景執行,就會發生「暖啟動」。冷啟動需要系統處理大部分作業,因為系統必須從儲存空間載入各種項目並初始化應用程式。因此,請設法將冷啟動的時間設為在 500 毫秒以下。

  • 讓 P95 和 P99 延遲時間非常接近中位數延遲時間。如果應用程式需要很長的時間才能啟動,會導致使用者體驗不佳。此外,在應用程式啟動的重要路徑中,處理序間通訊 (IPC) 和不必要的 I/O 可能會遭遇鎖定爭用的情況,並造成這些不一致的問題。

捲動時卡頓

「卡頓」一詞是指系統無法依要求的頻率 (例如 60 Hz 或更高) 及時建構和提供影格,導致畫面出現斷斷續續的情況。卡頓問題在捲動時最容易出現,舉例來說,因為應用程式轉譯內容所需的時間比系統畫面的持續時間還長,所以畫面移動時會出現卡頓現象。卡頓 當移動在一或多個影格中暫停時會顯示,因為 應用程式顯示內容所需的時間比系統畫面的持續時間還長。

應用程式的刷新率須定為 90 Hz。傳統的轉譯率為 60 Hz,但許多新型的裝置在使用者互動 (例如捲動) 時都是在 90 Hz 的模式下運作,而且有些裝置甚至支援更高的頻率 (最高 120 Hz)。

如要查看裝置在特定時間的刷新率,請依序輕觸「偵錯」部分的「開發人員選項」>「顯示刷新率」,啟用在畫面上疊加顯示刷新率的功能。

轉換不順暢

這個問題會在互動期間發生,例如切換分頁或載入新活動時。此類轉換的動畫應自然流暢,不得出現延遲或視覺效果閃爍的情況。

電源效率不佳

執行作業會消耗電池電力,而執行不必要的作業會降低電池續航力。

記憶體配置 (在程式碼中建立新物件) 可能會導致系統作業負載增加。這是因為配置作業不僅須透過 Android 執行階段 (ART) 完成,稍後釋出這些物件 (「垃圾收集」) 也需要時間與操作。所幸,現在的配置和收集速度都比以前更快,效率也更高,對於暫存物件而言更是如此。因此,儘管以往的最佳做法是盡可能避免配置物件,現在我們會建議您以最適合應用程式和架構的方式執行操作;考量到 ART 的能力,冒著風險使用無法維護的程式碼來減少配置,並不是最理想的做法。

不過,我們建議的做法須耗費一定工夫,因此請留意若在內部迴圈中配置多個物件,可能會導致效能問題。

辨別問題

辨別效能問題並進行補救的建議工作流程如下:

  1. 辨別並檢查下列關鍵使用者旅程:
    • 常見的啟動流程,包括透過啟動器和通知啟動的情形。
    • 使用者捲動資料的畫面。
    • 畫面之間的轉換。
    • 長時間執行的流程,例如導航或播放音樂。
  2. 在上述流程期間使用以下偵錯工具進行檢查:
    • Perfetto:可讓您利用精確的時間資料瞭解整部裝置中的運作情況。
    • 記憶體分析器:可讓您查看記憶體配置的發生情形 相關的所有節點
    • Simpleperf:透過火焰圖檢視正在使用的函式呼叫 在特定時間範圍內最多的 CPU 使用率。只要發現某些事物 在 Systrace 中花費的時間較長,但你不知道原因為何 可提供額外資訊

如要瞭解這些效能問題並進行偵錯,請務必手動對個別測試偵錯。以上步驟無法以分析匯總資料取代。不過,在自動化測試和實際環境中設定指標收集作業也很重要,因為這可協助您瞭解使用者實際可看到的畫面,並找出可能發生迴歸的時間點:

  • 啟動流程
  • 卡頓
    • 實際環境指標
      • Play 管理中心影格指標:您無法在 Play 管理中心將指標範圍縮小至特定使用者歷程,回報內容僅會說明應用程式的整體卡頓情形。
      • 使用 FrameMetricsAggregator 自訂評估:您可以在特定工作流程中使用 FrameMetricsAggregator 記錄卡頓指標。
    • 研究室測試
      • 使用 Macrobenchmark 捲動
      • Macrobenchmark 會使用包含單一使用者歷程的 dumpsys gfxinfo 指令收集影格時間。如要瞭解特定使用者歷程中卡頓的不同情況,這是可行的方式。RenderTime 指標會醒目顯示影格的繪製時間,在辨識迴歸或改善方面,此指標比卡頓影格數量更為重要。

應用程式連結是一種以網站網址為依據的深層連結,且經過驗證屬於您的網站。應用程式連結可能受到的原因如下: 以防止驗證失敗

  • 意圖篩選器範圍:僅針對符合以下條件的網址新增 autoVerify 至意圖篩選器 應用程式能做出回應
  • 未經驗證的通訊協定切換:未經驗證的伺服器端和子網域重新導向會被視為安全性風險,並導致驗證失敗。造成所有 autoVerify 個連結失敗。例如將連結從 HTTP 重新導向至 HTTPS 例如從 example.com 改為 www.example.com,如未驗證 HTTPS 連結 導致驗證失敗請務必新增意圖,驗證應用程式連結 篩選器。
  • 不可驗證的連結:加入無法驗證的連結來進行測試, 會導致系統無法為應用程式驗證應用程式連結。
  • 不穩定的伺服器:請確認您的伺服器可連線至用戶端應用程式。

設定應用程式進行效能分析

應用程式的基準測試必須正確設定,才能獲得可重現的正確結果並做出後續行動。請盡可能使用最接近實際工作環境的系統,同時抑制雜訊來源。下列各節說明準備測試設定時可以採用的 APK 與系統步驟,其中有些步驟僅適用於特定用途。

追蹤點

應用程式可以透過自訂追蹤事件檢測程式碼。

系統擷取追蹤記錄時,追蹤記錄在每個區段中都會產生少許額外負荷 (約 5 μs),因此請避免在每種方法中都加入追蹤記錄。追蹤記錄大型工作區塊 (>0.1 毫秒),就足以提供重要的瓶頸深入分析。

APK 注意事項

偵錯變化版本可協助您進行疑難排解,還可以透過符號方式提供堆疊樣本,但這會對效能造成嚴重影響。在搭載 Android 10 (API 級別 29) 以上版本的裝置中,您可以使用資訊清單中的 profileable android:shell="true",啟用發布子版本的剖析功能。

請使用實際執行等級的程式碼縮減設定。根據用途 可能會對應用程式效能產生重大影響。只有部分通知 ProGuard 設定會移除追蹤點,因此建議您移除這些追蹤點 以及要執行測試的設定

編譯

請將裝置端應用程式編譯為已知狀態 (通常是 speedspeed-profile)。背景及時 (JIT) 活動可能造成重大 造成效能上的負擔,而且重新安裝 APK 時經常會發生這種情況 測試期間執行編譯操作的指令如下:

adb shell cmd package compile -m speed -f com.google.packagename

speed 編譯模式會完整編譯應用程式;speed-profile 模式則會根據設定檔編譯應用程式,此設定檔中含有應用程式使用期間所收集的已用程式碼路徑。持續以正確方式收集設定檔可能並不容易,因此如果您決定使用這些設定檔,請確認設定檔收集的內容符合您預期。設定檔位於以下位置:

/data/misc/profiles/ref/[package-name]/primary.prof

Macrobenchmark 可讓您直接指定編譯模式

系統注意事項

如要進行低層級和高保真的評估,請校準裝置。建議您在相同的裝置和相同的 OS 版本中執行 A/B 版本比較作業,因為即便使用同樣的裝置類型,效能也可能會有顯著變化。

在已解鎖裝置中,請考慮使用 lockClocks 指令碼進行 Microbenchmark 測試。此外,指令碼也可以執行以下操作:

  • 將 CPU 設為固定頻率。
  • 停用小型核心並設定 GPU。
  • 停用熱節流。

使用 lockClocks 指令碼的這個方法不適合以使用者體驗為重的測試 (例如應用程式啟動、DoU 測試和卡頓測試),但對減少 Microbenchmark 測試中的雜訊而言,卻是不可或缺的一環。

建議盡可能使用 Macrobenchmark 等測試架構。 以減少測量中的雜訊,避免評估不準確。

應用程式啟動速度緩慢:非必要的 Trampoline 活動

Trampoline 活動可能會無端延長應用程式啟動時間,因此請務必瞭解應用程式是否涉及這類活動。在以下追蹤記錄範例中,activityStart 後面緊接著令另一個 activityStart,且第一個活動沒有繪製任何影格。

alt_text 圖 1. 顯示 Trampoline 活動的追蹤記錄。

這種情況在通知進入點和一般應用程式的啟動進入點都可能發生,而且通常可以透過重構來解決。舉例來說,如果您使用該活動在另一個活動執行前執行設定,請將這個程式碼分解到可重複使用的元件或程式庫中。

非必要配置觸發常用 GC

您可能會發現垃圾收集 (GC) 的發生頻率比 Systrace 中預期的高。

以下範例顯示,在長時間執行的作業期間,每 10 秒是一個指標,代表應用程式可能遭到不必要的分配,但有時仍會持續運作:

alt_text 圖 2. 顯示 GG 事件間隔的追蹤記錄。

您可能也會發現,在使用記憶體分析器時,特定呼叫堆疊會占據大部分的分配比例。您不需要主動刪除所有配置,因為這樣可能會導致程式碼更難以維護。不妨改從使用分配熱點開始。

Janky 頁框

圖形管線的複雜度相對較高,為了判斷使用者最後是否看見捨棄的影格,可能會有些許細微的影響。在某些情況下,平台可以使用緩衝功能來「找回」影格。不過您可以忽略大部分的細微差異,直接從應用程式的角度找出有問題的影格。

如果繪製的影格幾乎都不是在應用程式中完成,Choreographer.doFrame() 追蹤點的間隔在 60 FPS 裝置上就會是 16.7 毫秒:

alt_text 圖 3. 顯示頻繁快速影格的追蹤記錄。

縮小並瀏覽追蹤記錄時,有時會發現影格完成處理的時間比較長,但因為沒有超過配額的 16.7 毫秒,所以還是可以接受:

alt_text 圖 4. 顯示頻繁快速影格,且有定期突發工作的追蹤記錄。

如果您在規律的間隔中看到一處突然中斷,那就是卡頓的影格,如圖 5 所示:

alt_text 圖 5.顯示卡頓影格的追蹤記錄。

您可以練習如何辨別卡頓影格。

alt_text 圖 6. 顯示更多卡頓影格的追蹤記錄。

在某些情況下,您需要放大檢視追蹤點,才能進一步瞭解哪些檢視畫面正在加載,或 RecyclerView 正在執行哪些操作。在其他情況下,則可能需要進一步檢查。

如要進一步瞭解如何識別卡頓影格、偵錯並找出原因,請參閱「轉譯速度緩慢」。

RecyclerView 常見錯誤

使整個 RecyclerView 的備份資料失效,可能會因為 可能會導致影格轉譯時間過長和卡頓您應該改變做法,確保只有已變更的資料失效,盡可能減少需更新的檢視畫面數目。

請參閱「呈現動態資料」,瞭解如何避免成本高昂的 notifyDatasetChanged() 呼叫,這類呼叫會導致內容更新而非全面取代。

如果您無法正確支援每個巢狀的 RecyclerView,可能會導致內部 RecyclerView 每次都要全部重建。每個巢狀結構 內部 RecyclerView 必須設定 RecycledViewPool,以確保 可在每個內部 RecyclerView 之間回收。

如果預先擷取的資料量不足,或是未及時預先擷取,使用者就可能需要等候伺服器傳來更多資料,才能流暢捲動到清單底部。雖然技術上來說這不算卡頓,因為操作仍然符合影格顯示期限,但仍建議您修改預先擷取的時間和數量,讓使用者不必等候資料顯示。這麼一來,使用者體驗也就能大幅提升。

為應用程式偵錯

以下是對應用程式效能進行偵錯的各種方法。請觀看以下影片,概略瞭解系統追蹤功能和使用 Android Studio 分析器。

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

請參閱「應用程式啟動時間」,大致瞭解應用程式啟動程序,並 請觀看以下影片,概略瞭解系統追蹤。

您可以在下列階段區分啟動類型:

  • 冷啟動:開始建立沒有儲存狀態的新程序。
  • 暖啟動:重複使用程序時重新建立活動,或 就會以儲存的狀態重新建立程序。
  • 熱啟動:重新啟動活動,並從展開開始。

建議您使用裝置上的系統追蹤應用程式擷取系統追蹤記錄。如果是 Android 10 以上版本,請使用 Perfetto。如果是 Android 9 以下版本,請使用 Systrace。我們也建議您使用網頁式 Perfetto 追蹤記錄檢視器。詳情請參閱:系統總覽 追蹤記錄

建議您留意以下事項:

  • 監控爭用:受監控保護資源的競爭可能會帶來 可能會明顯延遲
  • 同步綁定資料傳輸:從應用程式的主要路徑中找出不必要的資料傳輸。如果必要交易費用高昂,請考慮處理 並與相關平台團隊合作進行改善

  • 並行 GC:這是常見且影響相對較低的資源,但如果您的資源 可以考慮使用 Android Studio 記憶體研究 分析器。

  • I/O:檢查啟動期間執行的 I/O,並尋找較嚴重的停頓問題。

  • 其他執行緒上的重大活動:這些活動可能會幹擾 UI 執行緒, 因此請留意啟動期間的背景工作

建議您在啟動程序完成後呼叫 reportFullyDrawn 改進應用程式啟動指標報告的觀點。請參閱時間 的完整顯示畫面一節,進一步瞭解如何使用 reportFullyDrawn。 您可以透過 Perfetto 追蹤記錄處理器,擷取 RFD 定義的開始時間。 並發出使用者可見的追蹤事件

在裝置上使用系統追蹤

您可以使用名為「系統追蹤」的系統層級應用程式,在裝置上擷取系統追蹤記錄。這個應用程式可讓你直接錄製裝置上的追蹤記錄 便無需插上電源或連上「adb

使用 Android Studio 記憶體分析器

您可以使用 Android Studio 記憶體分析器檢查記憶體流失或不當使用模式可能造成的記憶體壓力。可讓您即時查看物件配置情況。

您可以使用 記憶體分析器會追蹤 GC 發生的原因和頻率。

如要剖析應用程式記憶體,請執行下列步驟:

  1. 偵測記憶體問題。

    針對您要著重的使用者歷程,記錄記憶體分析工作階段。請查看物件計數是否持續增加 (如圖 7 所示),這最終會導致 GC 作業 (如圖 8 所示)。

    alt_text 圖 7. 正在增加物件數量。

    alt_text 圖 8. 垃圾收集。

    找出會增加記憶體壓力的使用者歷程後,請分析記憶體壓力的根本原因。

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

    在時間軸中選取範圍,以視覺化的方式呈現配置淺層大小:如圖 9 所示。

    alt_text 圖 9.Allocations淺層 值 Size

    這些資料的分類方式有很多種。以下是一些線上旅遊入口網站的使用者故事範例 以及如何運用這項資料檢視來分析問題

    • 依類別排序:如果您想找出會產生物件的類別,而這些物件會從記憶體集區快取或重複使用,這會很實用。

      舉例來說,如果您發現一個應用程式建立了 2,000 個類別的物件 「Vertex」則將配置數量增加 2,000 而在依類別排序時會看到此資料如果想重複使用 為了避免產生垃圾 請實作記憶體集區

    • 依呼叫堆疊編排:當記憶體配置到熱路徑,例如位於迴圈內或有特定功能需配置多項工作,依呼叫堆疊編排會是實用做法。

    • 淺層大小:只會追蹤物件本身占用的記憶體。很實用 用於追蹤大部分僅由原始值組成的簡易類別。

    • Retained Size:顯示因物件和參照而產生的記憶體總量 物件只會參照該物件很適合用來追蹤記憶體 這是因物體複雜而造成的壓力。如要取得這個值,請擷取完整記憶體 傾印 (如圖 10 所示),並新增「Retained Size」資料欄,如 如圖 11 所示

      alt_text 圖 10. 完整記憶體傾印。

      「保留大小」欄。
      圖 11. 保留大小欄。
  3. 評估最佳化措施的影響。

    GC 更顯而易見,且更容易評估記憶體的影響 以及最佳化調整當最佳化作業成功釋放記憶體壓力,您會看到次數較少的 GC。

    如要評估最佳化的影響,請在分析器時間軸中評估 總而言之隨後,GC 所需的時間較長。

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

    • 如果應用程式不會持續執行,則記憶體不足的關閉情形可能會降低 就會引發記憶體壓力
    • 減少垃圾收集值有助於改善卡頓指標,尤其是在 P99 中。這是因為垃圾收集事件會造成 CPU 爭用情形,導致轉譯工作在垃圾收集期間遭到延遲。