前言: 随着項目的擴大和功能的增多,代碼沒有經過嚴格的調試和優化,要麼任性地卡頓運作,要麼就低調地崩潰,最後導緻使用者用着不開心,開發者也比較煩惱。
為了突破這個這個關卡其實并不難,首先開發者隻要在Xcode自帶的監控調試工具 Instruments 上花點功夫就能夠讓代碼順暢運作。工欲善其事,必先利其器。Instrument對于iOS開發來說,是發現并且解決問題的一把利器。Instruments 提供了很多檢測功能,重點介紹一下我常用的幾大類:
- Analyze—靜态分析
- Leaks—記憶體洩露(動态記憶體洩露檢測)
- Time Profiler:檢測分析代碼的執行時間
界面顯示的原理
iOS裝置通常是60fps(每秒60幀),也就是說兩幀相隔的時間是1/60秒,大概16.7ms。在這16.7ms中,為了顯示一幀,需要如下工作
CPU計算好各個視圖的位置,大小,對圖檔進行解碼等,繪制成紋理交給GPU
GPU對收到的紋理進行混合,頂點變換,渲染到幀緩沖區
每16.7ms,一個時鐘信号到達,幀緩沖區取出一幀,顯示到螢幕。
也就是說,CPU或者GPU被大量占用的時候,都有可能在16.7ms中沒辦法完成一幀的繪制,導緻時鐘信号到來的時候,取得還是上一幀的内容,也就都有可能導緻界面卡頓
離屏渲染
在iOS中,渲染通常分為CPU和GPU渲染兩種,而GPU渲染又分為在GPU緩沖區和非GPU緩沖區兩種
CPU渲染(軟體渲染),CPU繪制成bitmap,交給GPU
GPU渲染(硬體渲染)
GPU緩沖區渲染
非GPU緩沖區渲染(額外開辟緩沖區)
通常,CPU渲染,和GPU非幀緩沖區内渲染統稱為離屏渲染。因為,CPU和幀緩沖區是為圖形圖像顯示做了高度優化的,速度較快。
什麼情況下會觸發離螢幕渲染?
用CoreGraphics的CGContext繪制的
在drawRect中繪制的,即使drawRect是空的
Layer具有Mask(比如圓角)或者Shadow
Layer的隔栅化shouldRasterize為True
文本(UILabel,UITextfield,UITextView,CoreText,UITextLayer等)
一,Analyze—靜态分析
顧名思義,靜态分析不需要運作程式,就能檢查到存在記憶體洩露的地方。
1. 使用方法:打開Xcode,command + shift + B;或者Xcode - Product - Analyze;
2. 常見的三種洩露情形:
(1)建立了一個對象,但是并沒有使用。Xcode提示資訊: Value Stored to 'number' is never read 。翻譯一下:存儲在'number'裡的值從未被讀取過。
(2)建立了一個(指針可變的)對象,且初始化了,但是初始化的值一直沒讀取過。Xcode提示資訊: Value Stored to 'str' during its initialization is never read
(3)調用了讓某個對象引用計數加1的函數,但沒有調用相應讓其引用計數減1的函數。Xcode提示資訊: Potential leak of an object stored into 'subImageRef' 。 翻譯一下:subImageRef對象的記憶體單元有潛在的洩露風險。
iOS性能分析和優化
二,Leaks—記憶體洩露
Leaks是動态的記憶體洩露檢查工具,需要一邊運作程式,一邊檢測。
1.使用方法: 進入Xcode,command + control + i ;或者Xcode - Xcode - Open Developer Tool - Instruments; 或者Xcode - Product - Profile。選擇Leaks。
一般用靜态分析檢查過的代碼,記憶體洩露都比較少。測試了有3個項目能點的按鈕都點了,能進的頁面都進的,Leaks也沒檢測到洩露。
三,Time Profile
1,打開Time Profile,然後運作想要分析的App
iOS性能分析和優化
2.進入主界面,上下滾動List,讓Time Profile采集資料,勾選右側的Separate by Thread,按線程區分Invert Call Tree,逆向Call Tree,友善我們檢視方法調用順序Hide System Libraries,隐藏系統的庫,因為通常系統的代碼并不會影響性能
iOS性能分析和優化
3.可以選擇一段時間,來分析這段時間CPU的使用情況
iOS性能分析和優化
4.找到占用時間最多的代碼
iOS性能分析和優化
然後,輕按兩下占用最多的這一行,進入實際的代碼,看看到底哪裡占用比較多
iOS性能分析和優化
這裡,我們看到是這一行代碼cell.testLabel?.attributedText = mutableAttr。
占用最多的CPU時間。
我們先來看下整個方法代碼,
TableViewCell其實很簡單,就一個ImageView(帶圓角,陰影),一個UILabel
cellForRowAtIndexPath裡會随機的生成100個字元,然後用AttributeText來讓UILabel顯示
乍一看,問題應該是這個随機生成100個字元的函數啊
iOS性能分析和優化
因為,每一次CellForRow調用的時候,都會計算100次。然後,我們實際分析的時候,發現其實100次對顯示來說,真不算什麼,也不是卡頓的原因。
那麼,為什麼設定attributeText占用時間這麼多呢?
其實很簡單,attributeText是建立在TextKit上的,由于每一次顯示都是随機的attributeText,每一次都要重新計算文本的大小,位置等等。另外,UIKit中,提供的文本渲染都是在CPU中進行的,渲染成Bitmap,然後交給GPU,是以導緻設定attributeText的時候,占用很多時間。
這裡不得不提到:一定不要過早優化,優化的時候盡量依賴于Instrument的分析結果,而不是自己的主觀感受。尤其當你還是個新司機的時候。