iOS 中的 CPU 和 GPU
在屏幕成像過程中酝枢,CPU 和 GPU 起著很重要的作用。
- CPU(Central Processing Unit,中央處理器)污筷,負(fù)責(zé)對(duì)象的創(chuàng)建和銷毀,對(duì)象屬性的調(diào)整乍赫,布局計(jì)算颓屑,文本的計(jì)算和排版,圖片的格式轉(zhuǎn)換和解碼耿焊,圖像的繪制揪惦。
- GPU(Graphics Processing Unit,圖形處理器)罗侯,負(fù)責(zé)紋理的渲染器腋。GPU 是一個(gè)專門為圖形高并發(fā)計(jì)算而量身定做的處理單元,比 CPU 使用更少的電來完成工作并且 GPU 的浮點(diǎn)計(jì)算能力要超出 CPU 很多钩杰。GPU 的渲染性能要比 CPU 高效很多纫塌,同時(shí)對(duì)系統(tǒng)的負(fù)載和消耗也更低一些,所以在開發(fā)中讲弄,我們應(yīng)該盡量讓 CPU 負(fù)責(zé)主線程的 UI 調(diào)動(dòng)措左,把圖形顯示相關(guān)的工作交給 GPU 來處理。
iOS 緩沖機(jī)制
iOS 使用的是雙緩沖機(jī)制避除。即 GPU 會(huì)預(yù)先渲染好一幀放入一個(gè)緩沖區(qū)內(nèi)(前幀緩存)怎披,讓視頻控制器讀取胸嘁,當(dāng)下一幀渲染好后,GPU 會(huì)直接把視頻控制器的指針指向第二個(gè)緩沖器(后幀緩存)凉逛。當(dāng)你視頻控制器已經(jīng)讀完一幀性宏,準(zhǔn)備讀下一幀的時(shí)候,GPU 會(huì)等待顯示器的 VSync 信號(hào)發(fā)出后状飞,前幀緩存和后幀緩存會(huì)瞬間切換毫胜,后幀緩存會(huì)變成新的前幀緩存,同時(shí)舊的前幀緩存會(huì)變成新的后幀緩存诬辈。
屏幕成像原理
時(shí)鐘信號(hào):垂直同步信號(hào)V-Sync / 水平同步信號(hào)H-Sync酵使。
屏幕成像就是垂直同步信號(hào)和水平同步信號(hào)一直發(fā)送。發(fā)出垂直同步信號(hào)(VSync)時(shí)焙糟,即將顯示一頁的數(shù)據(jù)凝化。水平同步信號(hào)(HSync)發(fā)出時(shí),就一行一行的顯示酬荞。
按照60FPS的刷幀率搓劫,每隔16ms就會(huì)有一次VSync信號(hào)。出現(xiàn)卡頓的原因就是發(fā)送VSync信號(hào)間隔時(shí)間過大混巧。
卡頓的原因
屏幕內(nèi)容是怎么顯示到屏幕上的枪向?
在 VSync 信號(hào)到來后,系統(tǒng)圖形服務(wù)會(huì)通過 CADisplayLink 等機(jī)制通知 App咧党,App 主線程開始在 CPU 中計(jì)算顯示內(nèi)容秘蛔,比如視圖的創(chuàng)建、布局計(jì)算傍衡、圖片解碼深员、文本繪制等。隨后 CPU 會(huì)將計(jì)算好的內(nèi)容提交到 GPU 去蛙埂,由 GPU 進(jìn)行變換倦畅、合成、渲染绣的。隨后 GPU 會(huì)把渲染結(jié)果提交到幀緩沖區(qū)去叠赐,等待下一次 VSync 信號(hào)到來時(shí)顯示到屏幕上。由于垂直同步的機(jī)制屡江,如果在一個(gè) VSync 時(shí)間內(nèi)芭概,CPU 或者 GPU 沒有完成內(nèi)容提交,則那一幀就會(huì)被丟棄惩嘉,等待下一次機(jī)會(huì)再顯示罢洲,而這時(shí)顯示屏?xí)A糁暗膬?nèi)容不變。這就是界面卡頓的原因文黎。
上面一段內(nèi)容出自 iOS 保持界面流暢的技巧惹苗,你可以在上述文章中對(duì)卡頓的原因做更深入的了解殿较。
在開發(fā)中,CPU 和 GPU 中任何一個(gè)壓力過大鸽粉,都會(huì)導(dǎo)致掉幀現(xiàn)象,所以在開發(fā)時(shí)抓艳,需要分別對(duì) CPU 和 GPU 壓力進(jìn)行評(píng)估和優(yōu)化触机。
卡頓優(yōu)化 - CPU
- 盡量用輕量級(jí)的對(duì)象,比如用不到事件處理的地方玷或,可以考慮使用CALayer取代UIView
- 不要頻繁地調(diào)用UIView的相關(guān)屬性儡首,比如frame、bounds偏友、transform等屬性蔬胯,盡量減少不必要的修改
- 盡量提前計(jì)算好布局,在有需要時(shí)一次性調(diào)整對(duì)應(yīng)的屬性位他,不要多次修改屬性
- Autolayout會(huì)比直接設(shè)置frame消耗更多的CPU資源
- 圖片的size最好剛好跟UIImageView的size保持一致
- 控制一下線程的最大并發(fā)數(shù)量
- 盡量把耗時(shí)的操作放到子線程:文本處理(尺寸計(jì)算氛濒、繪制),圖片處理(解碼鹅髓、繪制)
卡頓優(yōu)化 - GPU
- 盡量避免短時(shí)間內(nèi)大量圖片的顯示舞竿,盡可能將多張圖片合成一張進(jìn)行顯示
- GPU能處理的最大紋理尺寸是4096x4096,一旦超過這個(gè)尺寸窿冯,就會(huì)占用CPU資源進(jìn)行處理骗奖,所以紋理盡量不要超過這個(gè)尺寸
- 盡量減少視圖數(shù)量和層次
- 減少透明的視圖(alpha<1),不透明的就設(shè)置opaque為YES
- 盡量避免出現(xiàn)離屏渲染
離屏渲染
在OpenGL中醒串,GPU有2種渲染方式
- On-Screen Rendering:當(dāng)前屏幕渲染执桌,在當(dāng)前用于顯示的屏幕緩沖區(qū)進(jìn)行渲染操作
- Off-Screen Rendering:離屏渲染,在當(dāng)前屏幕緩沖區(qū)以外新開辟一個(gè)緩沖區(qū)進(jìn)行渲染操作
離屏渲染消耗性能的原因
- 需要?jiǎng)?chuàng)建新的緩沖區(qū)
- 上下文切換芜赌,離屏渲染的整個(gè)過程仰挣,需要多次切換上下文環(huán)境(CPU渲染和GPU切換),先是從當(dāng)前屏幕(On-Screen)切換到離屏(Off-Screen)缠沈;等到離屏渲染結(jié)束以后椎木,將離屏緩沖區(qū)的渲染結(jié)果顯示到屏幕上又需要將上下文環(huán)境從離屏切換到當(dāng)前屏幕。而上下文環(huán)境的切換是要付出很大代價(jià)的
哪些操作會(huì)觸發(fā)離屏渲染博烂?
- 光柵化香椎,layer.shouldRasterize = YES
- 遮罩,layer.mask
- 圓角禽篱,同時(shí)設(shè)置layer.masksToBounds = YES畜伐、layer.cornerRadius大于0
- 考慮通過CoreGraphics繪制裁剪圓角,或者叫美工提供圓角圖片
- 陰影躺率,layer.shadowXXX
- 如果設(shè)置了layer.shadowPath就不會(huì)產(chǎn)生離屏渲染
卡頓檢測
卡頓主要是因?yàn)樵谥骶€程執(zhí)行了比較耗時(shí)的操作玛界。我們可以使用 CADisplayLink 來監(jiān)視 CPU 的卡頓問題万矾,這是一個(gè) FPS 指示器。
參考文檔:
原文地址:淺談 iOS 性能優(yōu)化
更多文章請(qǐng)點(diǎn)擊:Articles