造成卡頓的原因最後都會反映到CPU時間上,可以把CPU時間分為兩種:系統時間和使用者時間。
使用者時間:執行使用者态應用程式代碼所消耗的時間
系統時間:執行核心态系統調用所消耗的時間,包括I/O、鎖、中斷以及其他系統調用的時間
CPU性能
擷取cpu核心數
cat /sys/devices/system/cpu/possible
擷取某個cpu的頻率
cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
卡頓問題分析名額
檢視cpu使用情況
/proc/stat 擷取整個系統的CPU使用情況
/proc/[pid]/stat 擷取某個程序的CPU使用情況
常用指令
top 檢視哪個程序是CPU消耗大戶
vmstat 實時動态監視作業系統的虛拟記憶體和CPU活動
strace 跟蹤某個程序所有的系統調用
CPU飽和度
CPU飽和度反應的是線程排隊等待CPU的情況,就是CPU的負載情況。
CPU飽和度會跟應用的線程數有關,如果啟動的線程過多,容易導緻系統不停的切換執行的線程,把時間浪費在上下文切換,每一次CPU上下文切換都需要重新整理寄存器和計數器。
檢視CPU上下文切換次數
vmstat
或
/proc/[pid]/schedstat
nr_voluntary_switches: 主動上下文切換次數,因為線程無法擷取所需資源導緻的上下文切換,最普遍的是IO
nr_involuntary_switches: 被動上下文切換次數,線程被系統強制排程導緻上下文切換,例如大量線程在搶占CPU
se.statistics.iowait_count:IO等待的次數
se.statistics.iowait_sum:IO等待的時間
線程優先級
線程優先級會影響Android系統的排程政策,它主要是由nice和cgroup類型共同決定的,nice值越低,搶占cpu時間片的能力越強。
注意是否存在高優先級的線程空等低優先級線程,例如主線程等待某個背景線程的鎖
Android卡頓排查工具
TraceView
Nanoscope
//安裝nanoscope 指令
brew tap uber/nanoscope
brew install nanoscope
nanoscope隻工作在Nanoscope模拟器或者安裝Nanoscope系統的裝置上
nanosscope emulator
//開始追蹤adb連接配接的裝置
nanoscope start
限制:
需要自己刷ROM,并且目前隻支援Nexus 6P,或者采用其提供的x86架構的模拟器
預設隻支援主線程采集,其他線程需要代碼手動設定
systrace
Simpleperf
卡頓現場
java實作
獲得java線程狀态
通過Thread的getState方法可以擷取線程狀态。
WAITING、TIME_WAITING、BLOCKED都是需要特别注意的狀态。
BLOCKED:是線程正在等待擷取鎖
WAITING: 是線程正在等待其他線程的喚醒動作。當一個線程處于waiting狀态時,不僅會釋放CPU資源,還會将持有的object鎖也同時釋放。
獲得所有線程堆棧
通過Thread.getAllStackTraces()拿到所有線程的堆棧,7.0之後該方法不會傳回主線程的堆棧。
BackgroundHandler屬于低優先級的背景線程,也就是主線程等待低優先級的背景線程
本質上Java線程的狀态其實是Native線程的一種映射。
Java線程狀态
NEW:當線程被建立,還沒有調用start方法時,線程就處于NEW狀态
RUNNABLE:該狀态表示線程具備所有運作條件,在運作隊列中準備作業系統的排程,或者正在運作。
BLOCKED:線程正在等待擷取java對象的螢幕,即線程正在等待進入由synchronized保護的方法或者代碼塊。
WAITING:處在該線程的狀态,正在等待某個事件的發生,隻有特定的條件滿足,才能獲得執行機會。
TIMED_WAITING:線程調用了限時版本的API,正在等待時間流逝,處在該狀态的線程,如果特定的事件發生或者時間流逝完畢,都會回複運作
TERMINATED:線程執行完畢,執行run方法正常傳回,或者抛出了運作時異常而結束,線程都會停留在這個狀态。