Android卡頓優化學習筆記

林三白發表於2020-09-24

造成卡頓的原因有很多種,但最終都會反應到CPU時間上,CPU時間分為使用者時間和系統時間。

  • 使用者時間:執行應用程式碼所需時間。
  • 系統時間:執行核心態系統程式碼所需時間,如I/O、鎖、中斷。

問題:當出現卡頓的時候,如何區分是應用的問題,還是系統的問題?

1. 卡頓問題分析指標

  • CPU使用率
    首先應該先檢視CPU使用率,通過/proc/[pid]/stat可以得到某個程式的CPU使用情況,會得到utime和stime兩個重要欄位。應用系統時間若超過30%,則應檢查是I/O過多還是其它系統呼叫問題。

Android中常用Linux命令:

命令作用
top檢視哪個程式是CPU消耗大戶
vmstat實時監視虛擬記憶體和CPU活動
strace跟蹤某個程式的所有系統呼叫
  • CPU飽和度
    這個標反應執行緒排隊等待CPU的情況,也就是CPU負載,該指標跟應用執行緒數有關,執行緒數過多會導致系統頻繁切換CPU上下文。也跟執行緒優先順序有關,CPU執行緒排程會對執行效率有非常大影響。
    可以使用vmstat命令或/proc/[pid]/schedstat檔案來檢視CPU上下文切換次數。
    proc/self/sched:
      nr_voluntary_switches:     
      主動上下文切換次數,因為執行緒無法獲取所需資源導致上下文切換,最普遍的是IO。    
      nr_involuntary_switches:   
      被動上下文切換次數,執行緒被系統強制排程導致上下文切換,例如大量執行緒在搶佔CPU。
      se.statistics.iowait_count:IO 等待的次數
      se.statistics.iowait_sum:  IO 等待的時間
    
    uptime命令可反應CPU在1分鐘、5分鐘、15分鐘內的平均負載,建議控制在0.7 * 核數內。

2. 卡頓問題分析工具

  • systrace工具
    它在一些系統呼叫上新增了探針,效能開銷低,但不支援應用程式程式碼的耗時分析,要想在systrace上增加應用程式的耗時分析,可以通過編譯時給每個函式插樁的方式實現,利用到Trace.beginSection和Trace.endSection兩個介面來統計應用程式程式碼耗時。

  • SimplePerf工具
    它可以看到所有Native程式碼的耗時,也封裝了systrace的功能,Android P以後的版本可無縫支援,使用火焰圖的方式展示分析結果。

  • AndroidStudio自帶的Profiler
    支援Call Chart和火焰圖兩種方式展示分析結果。

3. 卡頓的監控

主執行緒監控。

  • 訊息佇列
    因為looper在輪詢處理的時候會列印日誌,所以可以通過給looper設定一個自定義的Printer來統計耗時。

    // This must be in a local variable, in case a UI event sets the logger
    final Printer logging = me.mLogging;
    if (logging != null) {
        logging.println(">>>>> Dispatching to " + msg.target + " " +
                msg.callback + ": " + msg.what);
    }
    
    ...
    //事件處理結束
    if (logging != null) {
        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    }
    

    另一種方案是通過一個監控執行緒每隔一秒就向主執行緒訊息佇列頭部新增一條空訊息,假設 1 秒後這個訊息並沒有被主執行緒消費掉,說明阻塞訊息執行的時間在 0~1 秒之間。換句話說,如果我們需要監控 3 秒卡頓,那在第 4 次輪詢中頭部訊息依然沒有被消費的話,就可以確定主執行緒出現了一次 3 秒以上的卡頓。

  • systrace編譯插樁
    通過在函式入口和出口新增耗時監控程式碼實現監控,因為監控程式碼是一樣的,所以要給每個方法新增獨立的ID作為引數,過濾return、i++等簡單函式,對於呼叫頻繁的函式不計入統計減少效能損耗。缺點是無法監控系統程式碼的耗時。

  • profilo
    FaceBook開源的庫,功能強大,效能基本沒有影響,捕捉資訊全,整合了atrace的功能,可快速獲取Java堆疊,需要注意相容性。

    其它監控

    • 幀率監控
      重點獲取凍幀率這個指標,連續丟幀42幀以上稱為凍幀,凍幀率就是凍幀時間在所有時間的佔比。發生丟幀時獲取當前頁面資訊、view資訊、操作路徑上報後臺幫助排查。還可以根據activity、fragment分組採集平均幀率、凍幀率統計對比。
    • 生命週期監控
      監控Activity、Service、Receiver生命週期的耗時和呼叫次數;監控程式生命週期的啟動次數和耗時,可以看出某些程式是否被頻繁拉起。監控手段:外掛化技術Hook、編譯時插樁(Aspect、ASM、ReDex)。
    • 執行緒監控
      其它執行緒過多佔用CPU會影響主執行緒的UI響應能力,因此應該監控如下兩個指標。
      第一個:執行緒數量,監控執行緒數量的多少和建立方式。
      第二個:執行緒時間,監控使用者時間utime、系統時間stime和優先順序,主要看哪些執行緒佔用過多CPU。

相關文章