一、在線性能監(jiān)控的必要性
現在市面上有各種品牌的手機,有高端機,也有低端機,手機的配置、性能、運行的系統版本都是不一樣的,APP在有的手機上運行流暢,而在有的手機上運行卻會卡頓,所以有的用戶會抱怨APP用的時候怎么這么卡,這樣就會暴露出我們的代碼寫得可能有性能問題,從而有必要收集一些信息,找出卡頓的原因。收集到這些信息,有利于我們分析并解決,在下一個版本發(fā)布后,給用戶帶來更好的使用體驗。
二、性能監(jiān)控的指標
一般從幾下幾個方面監(jiān)控應用的性能:
1、CPU:如果長時間的使用CPU,會極大的消耗電量,手機也會發(fā)熱,影響用戶體驗。一般是程序 中有BUG或是寫的代碼性能很差,需要優(yōu)化。
2、內存:內存使用過大容易被系統殺掉,也容易出現OOM而使應用崩潰,一般是程序中出現了內存泄漏,或者沒有對內存做過優(yōu)化。
3、幀率FPS:如果幀率小于60幀每秒,就會造成應用卡頓,也是影響用戶體驗的。一般是由于過渡繪制造成的,需要對繪制的代碼進行優(yōu)化。
三、各平臺(IOS/Android)對各個指標監(jiān)控的實現方案
3.1、Android指標監(jiān)控實現方案
CPU的使用率
Android中可以獲取CPU總的使用時間,每個進程所用CPU時間以及進程中每個線程的CPU使用時間,它沒有提供API接口,可以直接在應用中讀取/proc/stat,/proc/pid/stat,/proc/pid/task/tid/stat這幾個文件來獲取,不需要root權限。一些開源的性能統計工具也是通過這種方法來顯示CPU使用率的,比如網易的Emmagee。
1、獲取CPU總使用率
在proc/stat中有詳細的CPU使用情況.詳細格式如下:
CPU 16394633 4701297 9484146 36314562 70851 1797 202347 0 0 0
CPU后面的幾位數字分別是
user從系統啟動開始累計到當前時刻,處于用戶態(tài)的運行時間,不包含nice值為負進程。
nice從系統啟動開始累計到當前時刻,nice值為負的進程所占用的CPU時間
system從系統啟動開始累計到當前時刻,處于核心態(tài)的運行時間
idle從系統啟動開始累計到當前時刻,除IO等待時間以外的其它等待時間
iowait從系統啟動開始累計到當前時刻,IO等待時間
irq從系統啟動開始累計到當前時刻,硬中斷時間
softirq從系統啟動開始累計到當前時刻,軟中斷時間
在某個時間T1的CPU總時間為:
totalCpuTime1 = user1 + nice1 + system1 + idle1 + iowait1 + irq1 + softirq1
在時間T2的CPU總時間為(T2 > T1):
totalCpuTime2 = user2 + nice2 + system2 + idle2 + iowait2 + irq2 + softirq2
CPU總使用率的算法是:
100*((totalCpuTime2-totalCpuTime1) - (idel2-idel1)) / (totalCpuTime2-totalCpuTime1)
2、獲取進程的CPU使用率
/proc/pid/stat中則是該pid進程的CPU使用情況.詳細格式如下:
2757 (zenmen.palmchat) S 549 549 0 0 -1 1077952832 1674191 173040 7885 4062265 19589 99 49412
其中粗體的四位數字分別是:
utime 該任務在用戶運行狀態(tài)的時間
stime 該任務在核心運行的時間
cutime 所有已死線程在用戶狀態(tài)運行狀態(tài)的時間
cstime 所有已死線程在核心的運行時間
所以進程的CPU使用時間processCpuTime為這個四個屬性的和.
在T1時,processCpuTime1 = utime1 + stime1 + cutime1 + cstime1
在T2時,processCpuTime2 = utime2 + stime2 + cutime2 + cstime2
所以進程所占CPU的使用率算法是:
100*(processCpuTime2-processCpuTime1) / (totalCpuTime2-totalCpuTime1)
3、獲取進程中線程的CPU使用率
/proc/pid/task/tid/stat中是該pid進程中tid線程的CPU使用情況,格式和進程CPU使用的格式是一樣的,
3810 (fileDecodingQue) S 549 549 0 0 -1 1077952576 269 173040 0 40 0 0 99 494 20 0
線程的CPU時間為:threadCpuTime = utime + stime
線程的CPU使用率算法是:
100*(threadCpuTime2-threadCpuTime1) / (totalCpuTime2-totalCpuTime1)
內存使用
Android提供有API可以獲取系統總內存大小及當前可用內存大小,以及獲取應用中內存的使用情況。
1、獲取系統總內存大小及可用內存大小
ActivityManager.MemoryInfo有以下幾個Field:
totalMem:表示總內存大小
availMem:表示系統剩余內存
2、獲取應用使用的內存大小
Debug.MemoryInfo.getTotalPss(),返回的是KB
監(jiān)控幀率FPS
Android系統從4.1(API 16)開始加入Choreographer這個類來控制同步處理輸入(Input)、動畫(Animation)、繪制(Draw)三個操作。其實UI顯示的時候每一幀要完成的事情只有這三種。Choreographer接收顯示系統的時間脈沖(垂直同步信號-VSync信號),在下一個幀渲染時控制執(zhí)行這些操作。收到VSync信號后,順序執(zhí)行3個操作,然后等待下一個信號,再次順序執(zhí)行3個操作。假設在第二個信號到來之前,所有的操作都執(zhí)行完成了,即Draw操作完成了,那么第二個信號來到時,此時界面將會更新為第一幀的內容,因為Draw操作已經完成了。否則界面將不會更新,還是現實上一個幀的內容,表示丟幀了。丟幀是造成卡頓的原因。
通過 Choreographer 類設置它的 FrameCallback,可以在每一幀被渲染的時候記錄下它開始渲染的時間,每一次同步的周期為16ms,代表一幀的刷新頻率,一次界面渲染會回調 FrameCallback的doFrame(longframeTimeNanos)方法,如果兩次 doFrame 之間的間隔大于16ms說明丟幀了。用這種方法,可以實時監(jiān)控應用的丟幀情況。
四、監(jiān)控日志上傳
對于CPU,可以每隔一段時間去獲取APP進程CPU時間,也可以針對一些場景手動獲取??梢栽O定一個閾值,比如大于50%的時候,將各個線程名及線程占用的CPU時間一起保存到日志中。
對于內存,在加載圖片、視頻、聲音等這些比較耗費內存的資源的時候去獲取一次應用內存占用及系統剩余內存保存到日志中。
幀率FPS是可以在程序中實時監(jiān)控的,可以在Activity start時開始監(jiān)控,當檢測到丟幀時保存丟帆的個數,在Activity stop時停止監(jiān)控,取最大的丟幀個數,再將Activity類名一起保存到日志中。