頁面卡頓是由哪些原因導致的?
1.死鎖: 主線程拿到鎖A, 需要獲取鎖B, 而同時子線程拿了鎖B, 需要鎖A, 這時主線程等待鎖B的釋放, 子線程等待鎖A的釋放, 相互等待.
2.搶鎖: 主線程需要訪問DB, 而這時某個子線程往DB插入數(shù)據(jù). 通常搶鎖的體驗就是卡頓一陣子就恢復了.
3.主線程大量IO: 主線程為了方便直接寫入大量數(shù)據(jù), 導致頁面卡頓.
4.主線程大量計算: 程序中的算法不合理, 大量循環(huán)等操作, 導致主線程某個函數(shù)占用大量CPU.
5.大量的UI繪制: 復雜的UI, 圖文混排等, 帶來大量的UI繪制.
卡頓問題怎么定位?
1.死鎖一般會伴隨Crash, 我們可以通過Crash日志進行分析.
2.搶鎖的問題不太好辦, 我們能將鎖等待的時間打印出來, 但我們還需要知道是誰占用了鎖, 可以檢測Runloop的執(zhí)行,觀察耗時.
3.大量的IO可以在函數(shù)開始結束打點, 將函數(shù)占用時間打到日志中.
4.線程大量計算同理也可以將耗時記錄到日志中.
5.大量UI繪制一般是難免的, APP中總會有復雜頁面的繪制, 我們可以用AsnycDisplayKit等框架進行預排版,異步繪制,圖片解碼等.
如果我們能將上述問題發(fā)生時線程的堆棧信息捕捉下來, 那么就能快速定位到問題, 從而問題迎刃而解. 所以, iOS卡頓檢查的思路就是創(chuàng)建一個子線程, 監(jiān)控主線程Runloop的執(zhí)行, 觀察執(zhí)行耗時是否超過預閾值, 如果有就立即記錄線程堆棧.
如何獲取所有線程的堆棧呢?
很有名的PLCrashReporter, 拿來主義就好!
這里也寫了一個監(jiān)測主線程RunLoop的demo
如何判斷主線程是否發(fā)生了卡頓?
FPS降低
CPU占用率很高
主線程Runloop執(zhí)行了很久
FPS能夠兼容后面兩個特征, 但在實際操作過程中發(fā)現(xiàn)FPS不好衡量抖動比較大. 對于搶鎖或者大量IO的情況, 光靠CPU是不行的, 所以一般檢測判斷, CPU占用是否超過了100%, 主線程Runloop執(zhí)行是夠超過閾值.
具體原因和思路如上, 下面貼出微信內(nèi)存監(jiān)控解決方案:
關于卡頓檢測, 世界上最好的免費APM平臺Fabric卻沒有, 國內(nèi)騰訊的bugly, 網(wǎng)易云捕等提供了類似的功能.