1. 工具選擇
CPU Profiler、Systrace、StrictMode
原因復雜:代碼、內存、繪制、IO均有可能導致卡頓。難以定位。
不易復現(xiàn):當時場景強相關。
CPU Profiler:圖形的形式展示執(zhí)行時間、調用棧等。信息全面,包含所有線程。整體會變慢。
使用方式:
Debug.startMethodTracing("");
Debug.stopMethodTracing("");
生成文件在SD卡:Android/data/packagename/files
Systrace:監(jiān)控和跟蹤Api調用、線程運行情況,生成Html報告
API 18以上使用,推薦TraceCompat
python systrace.py -t 10 [other-options] [categories]
https://developer.android.com/studio/command-line/systrace#command_options
優(yōu)點:輕量級、開銷小。直觀反映CPU利用率。給出建議(Alert)
StrictMode:嚴苛模式,Android提供的一種運行時檢測機制。方便強大,容易被忽視。
包含:線程策略和虛擬機策略檢測。
線程策略:自定義的耗時調用,detectCustomSlowCalls()
磁盤讀取操作,detectDiskReads
網(wǎng)絡請求操作
虛擬機策略:
Activity泄漏,detectActivityLeaks()
Sqlite泄漏,detecteLeakedSqliteObjects
檢測實例數(shù)量,setClassInstanceLimit()
2. 自動化卡頓檢測方案及優(yōu)化
原理:一個線程只有一個Looper
mLogging對象在每個message處理前后被調用
主線程發(fā)生卡頓,是在dispatchMessage執(zhí)行耗時操作
具體實現(xiàn):
1)Looper.getMainLooper().setMessageLogging();
2)匹配>>>>>Dispatching,閾值時間后執(zhí)行任務(獲取堆棧)
3)匹配<<<<<Finished,任務啟動之前取消掉
AndroidPermormanceMonitor實戰(zhàn)(blockcanary)
非侵入性的性能監(jiān)控組件,通知形式彈出卡頓信息
問題及優(yōu)化
卡頓了,但卡頓堆??赡懿粶蚀_。和OOM一樣,最后的堆棧只是表象,不是真正的問題。
優(yōu)化:獲取監(jiān)控周期內的多個堆棧,而不僅是最后一個。
startMonitor -> 高頻采集堆棧-> endMonitor -> 記錄多個堆棧 -> 上報
海量卡頓堆棧處理
高頻卡頓上報量太大,服務端有壓力。
分析:一個卡頓下多個堆棧大概率有重復
解決:對一個卡頓下堆棧進行hash排重,找出重復的堆棧。
效果:極大的減少展示量且找到真正發(fā)生問題的堆棧。
3. ANR分析與實戰(zhàn)
KeyDispatchTimeout:5s
BroadcastTimeout:前臺10s,后臺60s
ServiceTimeout:前臺20s,后臺200s
ANR執(zhí)行流程:發(fā)生ANR,進程接收異常終止信號,開始寫入進程ANR信息。
彈出ANR提示框(ROM表現(xiàn)不一)
ANR解決套路:
adb pull data/anr/traces.txt
存儲路徑。 根據(jù)此路徑來判斷是否ANR
詳細分析:cpu/io
線上ANR監(jiān)控方案
通過FileObserver 監(jiān)控文件變化,高版本會有權限問題
ANR-WatchDog
非侵入式ANR監(jiān)控組件
com.github.anrwatchdog:anrwatchdog:1.3.0
https://github.com/SalomonBrys/ANR-WatchDog
原理:
start -> post消息改值(主線程+1操作) -> 線程sleep
檢測值是否被修改 ->判斷ANR發(fā)生(沒有被修改 message沒有到即發(fā)生)
彌補高版本沒有權限讀取Trace.txt 的問題。結合使用
和BlockCanary區(qū)別:
BlockCanary監(jiān)控Msg。適合監(jiān)控卡頓。
ANR-WatchDog:看最終結果。適合補充ANR監(jiān)控。
3. 卡頓單點問題檢測方案
自動化卡頓檢測方案并不夠。很多操作的耗時并沒有達到卡頓閾值,感受同樣不佳但是不會拋出異常堆棧信息。
體系化解決方案務必盡早暴露問題。
單點問題:主線程IPC、DB IO、View繪制操作
IPC問題監(jiān)測:
監(jiān)測指標:IPC調用類型
調用耗時、次數(shù)
調用堆棧、發(fā)生線程。
常規(guī)方案:
IPC前后加埋點。不夠優(yōu)雅,容易忘記。維護成本大。
adb命令:
adb shell am trace-ipc start // 監(jiān)控的開始
adb shell am trace-ipc stop --dump-file /data/local/tmp/ipc-trace.txt
//結束,存放信息
adb pull /data/local/tmp/ipc-trace.txt // 導出
優(yōu)雅方案:
ARTHook 還是 AspectJ?
ARTHook 可以Hook系統(tǒng)方法。ASpectJ針對非系統(tǒng)方法。
IPC場景:PackageManger得到應用信息、get到設備的ID、AMS等等。
固定的調用方式,最后會調用到 “android.os.BinderProxy” transact方法
4. 如何實現(xiàn)界面秒開
首先通過Systrace(查看是否跑滿CPU),優(yōu)雅異步 + 優(yōu)雅延遲初始化。
異步Inflate、X2C、繪制優(yōu)化
提前獲取頁面數(shù)據(jù)
界面秒開率統(tǒng)計:
onCreate 到 onWindowFocusChanged
特定接口適配Activity
Lancet:輕量級 AOP框架
編譯速度快,支持增量編譯
API簡單,沒有任何多余代碼插入 apk
@Proxy 通常用與對系統(tǒng)API調用的Hook
@Insert 常用于操作 App與library的類
界面秒開監(jiān)控維度
1)onCreate到onWindowFocusChanged 兩方法調用的時間間隔。
總體耗時。
2)生命周期的耗時。
3)生命周期間隔的耗時
5. 優(yōu)雅監(jiān)控耗時盲區(qū)
生命周期間隔
onResume到Feed展示的間隔
舉例:postMessage,很有可能在Feed之前執(zhí)行
TraceView
特別適合一段時間內的盲區(qū)監(jiān)控
線程具體時間做了什么,一目了然。
TraceView適合現(xiàn)在,可以監(jiān)控系統(tǒng)Msg。
動態(tài)替換適合線上,只有應用自身的Msg
線上方案:
所有方法都是Msg,mLogging?沒有Msg具體堆棧
AOP切Handler方法?不清楚準確執(zhí)行時間
使用統(tǒng)一的Handler:定制具體方法
定制gradle插件,編譯器動態(tài)替換。
6. 卡頓優(yōu)化技巧總結初步
耗時操作:異步、延遲
布局優(yōu)化:異步Inflate、X2C、重繪解決
內存:降低內存占用,減少GC時間。
Log / TraceView的HeapTaskDesk
卡頓優(yōu)化工具建設
Systrace:看出CPU使用情況
TraceView:看出線程在特定時間做什么。相對開銷比較大。
StrictMode也是很強大的
自動化監(jiān)控工具建設。
Android Performance monitor。ANR - WatchDog
高頻采集,找出重復率高的堆棧。
卡頓監(jiān)控工具
單點問題:AOP、Hook
盲區(qū)監(jiān)控:gradle 編譯器替換。監(jiān)控所有主線程msg執(zhí)行耗時,以及調用堆棧 superHandler。
通過注解調整所有Handler的父類。
卡頓監(jiān)控指標:
卡頓率、ANR率、界面秒開時間
交互時間、生命周期時間
上報環(huán)境、場景信息!
7. 卡頓優(yōu)化模擬面試
1)你是怎么做卡頓優(yōu)化的?
體現(xiàn)出來不同階段的進步,結構化思維。
經(jīng)歷了一些階段,第一階段:系統(tǒng)工具定位、解決。
第二階段:自動化卡頓方案及優(yōu)化。
第三階段:線上卡頓及線下監(jiān)測工具建設。
2)你是怎么自動化的獲取卡頓信息的?
mLogging.println
不一定準確。可以高頻采集,找出重復堆棧!
3)卡頓的一整套解決方案是怎么做的?
線下(盡量早)、線上(全面自動化、異常感知靈敏度)工具相結合的方式
特定難點突破:單點問題、盲區(qū)監(jiān)控
SuperHandler