iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Mobile Development

Android 性能戰爭:從 Profiler 開始的 30 天優化實錄系列 第 17

# Day 17:【流暢度戰爭】 systrace/perfetto:終極卡頓分析神器

  • 分享至 

  • xImage
  •  

各位戰士,歡迎來到第十七天的戰場。在前一天的偵查任務中,我們學會了使用 Profile GPU Rendering 來發現那些飛越 16ms 生命線的「紅色警報」。我們知道了**「何時」發生了 Jank,但我們仍然不完全清楚「為何」**發生。

Profile GPU Rendering 就像是戰場上的哨兵,他能大喊「有敵人!」,但我們需要更強大的工具來回答接下來的問題:敵人是誰?有多少人?他們攜帶了什麼武器?

今天,我們將學習使用 Android 平台最強大的性能分析工具——Perfetto(其前身為 Systrace)。它不是望遠鏡,而是軍事衛星,能為我們拍下整個戰場在卡頓瞬間的、精確到微秒的「活動快照」。


什麼是 Perfetto / Systrace?

簡單來說,當你開始錄製一段 Trace(追蹤記錄)時,Android 系統會像一個高速攝影機,記錄下這段時間內系統各個部分的所有關鍵活動,包括:

  • CPU 調度:哪個執行緒在哪個 CPU 核心上運行。
  • 應用程式:你的 App 中每個執行緒(尤其是 UI Thread 和 RenderThread)正在執行哪個函式。
  • 圖像系統:畫面是如何被合成並發送到螢幕的。

Perfetto 是一個現代化的、基於網頁的 Trace 視覺化工具,它可以打開並解析這些由系統產生的複雜 Trace 檔案,用直觀的時間軸圖表呈現在我們面前。


如何捕獲 Trace 檔案

捕獲 Trace 的方式有幾種,我們介紹兩種最常用的。

方式一:使用 Android Studio Profiler (推薦)

這是最簡單、整合度最高的方式,適合絕大多數開發場景。

  1. 開啟 Android Studio 的 Profiler 視窗 (View > Tool Windows > Profiler)。
  2. 點擊 CPU 時間軸上的任意位置,進入 CPU Profiler。
  3. 在頂部的配置選項中,選擇 System Trace Recording
  4. 點擊 Record 按鈕。
  5. 立刻切換到你的應用,並重現那個會導致卡頓的操作(例如:快速滑動那個會掉幀的列表)。
  6. 操作完成後,點擊 Stop
  7. 稍等片刻,Android Studio 會自動解析 Trace 檔案並在視窗中顯示結果。

方式二:使用設備內建功能 (進階)

當卡頓難以在連接電腦時穩定重現,可以使用此方法。

  1. 在手機的「開發人員選項」中,找到並進入「系統追蹤」(System Tracing)。
  2. 設定你關心的「類別」(Categories),對於 UI 卡頓,請務必勾選 gfx (圖像)、view (視圖系統)、sched (CPU 調度)、input (輸入事件)。
  3. 點擊「錄製追蹤記錄」。
  4. 重現卡頓操作。
  5. 完成後,下拉通知欄,點擊通知來停止錄製
  6. 系統會提示你儲存 .perfetto-trace 檔案,將它分享到你的電腦上。
  7. 在瀏覽器中打開 Perfetto UI 網站:ui.perfetto.dev,將檔案拖曳進去即可分析。

分析 Trace:在 Perfetto UI 中揪出元兇

無論使用哪種方式,你最終都會看到一個類似的、充滿泳道圖的時間軸介面。它看起來很嚇人,但對於抓 Jank,我們只需要關注幾個關鍵部分:

https://ithelp.ithome.com.tw/upload/images/20251001/20168455ZCrKSIgaj1.png

  1. 找到你的應用程式:在左側的搜尋框中,輸入你 App 的套件名稱 (Package Name),Perfetto 會高亮顯示與你 App 相關的所有進程。

  2. 關注 FrameTimeline:在你的應用進程下,找到名為 FrameTimelineActual Timeline 的泳道。

    • 這條泳道用綠色黃色紅色的藥丸狀方塊顯示每一幀的狀態。
    • 綠色代表流暢。當你看到紅色黃色的方塊時,恭喜你,你已經精準定位到了發生 Jank 的那一幀!
  3. 分析 UI Thread:這永遠是你的重點偵查對象。

    • 點擊紅色/黃色的幀方塊,Perfetto 會自動幫你框選出對應的時間範圍。
    • 向下找到名為你的套件名稱的執行緒(這就是 UI Thread)。
    • 在該時間範圍內,你會看到一個很長的、名為 doFrameperformTraversals 的任務。這就是 Android 系統在一幀內繪製畫面的主要工作。
    • 點開它,你會看到更細分的 onMeasure, onLayout, onDraw 等任務。如果其中任何一個任務佔據了過長的時間(例如超過 10ms),它就是導致卡頓的直接原因
  4. 分析 RenderThread:UI Thread 的下方通常是 RenderThread。分析方法相同,檢查是否有異常耗時的任務。

實戰技巧:自訂追蹤標籤

為了讓 Trace 更清晰,你可以在你的程式碼中加入自訂的標籤。

import android.os.Trace

// 在 RecyclerView.onBindViewHolder 或其他你懷疑耗時的方法中
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    Trace.beginSection("MyAdapter.onBindViewHolder") // 開始標記
    
    // ... 你的原有耗時邏輯 ...
    
    Trace.endSection() // 結束標記
}

加上這段程式碼後,當你再次抓取 Trace 時,就能在 UI Thread 的時間軸上看到一個名為 "MyAdapter.onBindViewHolder" 的區塊,讓你一眼就看出是哪段程式碼出了問題。

今日總結

今天,我們掌握了性能分析的終極武器——Perfetto。我們學會了:
錄製 Trace:透過 Android Studio 或手機內建功能來捕獲系統活動快照。
定位 Jank:在 FrameTimeline 中找到代表掉幀的紅色/黃色方塊。
分析根源:在 UI Thread 中,找到與掉幀方塊對應時間點的、耗時過長的任務(如 onDraw 或自訂標籤)。
我們的作戰流程已經清晰:用視覺化工具發現煙霧,再用 Perfetto 的衛星快照定位火源。
既然我們已經擁有了精準定位敵人的能力,從明天開始,我們將學習各種具體的「殲滅戰術」。首先要攻克的,就是最常見的敵人之一:因佈局複雜導致的渲染性能問題。

我們明天見!


上一篇
# Day 16:【流暢度戰爭】偵測工具:開啟 GPU Overdraw 與 Profile GPU Rendering
下一篇
# Day 18:【流暢度戰爭】佈局優化的勝利:ConstraintLayout vs LinearLayout
系列文
Android 性能戰爭:從 Profiler 開始的 30 天優化實錄22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言