九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Android性能優(yōu)化典范(二)
Android性能優(yōu)化典范(一)
接上文:
5)Android, UI and the GPU

了解Android是如何利用GPU進(jìn)行畫面渲染有助于我們更好的理解性能問題。那么一個(gè)最實(shí)際的問題是:activity的畫面是如何繪制到屏幕上的?那些復(fù)雜的XML布局文件又是如何能夠被識別并繪制出來的?



Resterization柵格化是繪制那些Button,Shape,Path,String,Bitmap等組件最基礎(chǔ)的操作。它把那些組件拆分到不同的像素上進(jìn)行顯示。這是一個(gè)很費(fèi)時(shí)的操作,GPU的引入就是為了加快柵格化的操作。

CPU負(fù)責(zé)把UI組件計(jì)算成Polygons,Texture紋理,然后交給GPU進(jìn)行柵格化渲染。



然而每次從CPU轉(zhuǎn)移到GPU是一件很麻煩的事情,所幸的是OpenGL ES可以把那些需要渲染的紋理Hold在GPU Memory里面,在下次需要渲染的時(shí)候直接進(jìn)行操作。所以如果你更新了GPU所hold住的紋理內(nèi)容,那么之前保存的狀態(tài)就丟失了。

在Android里面那些由主題所提供的資源,例如Bitmaps,Drawables都是一起打包到統(tǒng)一的Texture紋理當(dāng)中,然后再傳遞到GPU里面,這意味著每次你需要使用這些資源的時(shí)候,都是直接從紋理里面進(jìn)行獲取渲染的。當(dāng)然隨著UI組件的越來越豐富,有了更多演變的形態(tài)。例如顯示圖片的時(shí)候,需要先經(jīng)過CPU的計(jì)算加載到內(nèi)存中,然后傳遞給GPU進(jìn)行渲染。文字的顯示更加復(fù)雜,需要先經(jīng)過CPU換算成紋理,然后再交給GPU進(jìn)行渲染,回到CPU繪制單個(gè)字符的時(shí)候,再重新引用經(jīng)過GPU渲染的內(nèi)容。動畫則是一個(gè)更加復(fù)雜的操作流程。

為了能夠使得App流暢,我們需要在每一幀16ms以內(nèi)處理完所有的CPU與GPU計(jì)算,繪制,渲染等等操作。
6)Invalidations, Layouts, and Performance

順滑精妙的動畫是app設(shè)計(jì)里面最重要的元素之一,這些動畫能夠顯著提升用戶體驗(yàn)。下面會講解Android系統(tǒng)是如何處理UI組件的更新操作的。

通常來說,Android需要把XML布局文件轉(zhuǎn)換成GPU能夠識別并繪制的對象。這個(gè)操作是在DisplayList的幫助下完成的。DisplayList持有所有將要交給GPU繪制到屏幕上的數(shù)據(jù)信息。

在某個(gè)View第一次需要被渲染時(shí),DisplayList會因此而被創(chuàng)建,當(dāng)這個(gè)View要顯示到屏幕上時(shí),我們會執(zhí)行GPU的繪制指令來進(jìn)行渲染。如果你在后續(xù)有執(zhí)行類似移動這個(gè)View的位置等操作而需要再次渲染這個(gè)View時(shí),我們就僅僅需要額外操作一次渲染指令就夠了。然而如果你修改了View中的某些可見組件,那么之前的DisplayList就無法繼續(xù)使用了,我們需要回頭重新創(chuàng)建一個(gè)DisplayList并且重新執(zhí)行渲染指令并更新到屏幕上。

需要注意的是:任何時(shí)候View中的繪制內(nèi)容發(fā)生變化時(shí),都會重新執(zhí)行創(chuàng)建DisplayList,渲染DisplayList,更新到屏幕上等一系列操作。這個(gè)流程的表現(xiàn)性能取決于你的View的復(fù)雜程度,View的狀態(tài)變化以及渲染管道的執(zhí)行性能。舉個(gè)例子,假設(shè)某個(gè)Button的大小需要增大到目前的兩倍,在增大Button大小之前,需要通過父View重新計(jì)算并擺放其他子View的位置。修改View的大小會觸發(fā)整個(gè)HierarcyView的重新計(jì)算大小的操作。如果是修改View的位置則會觸發(fā)HierarchView重新計(jì)算其他View的位置。如果布局很復(fù)雜,這就會很容易導(dǎo)致嚴(yán)重的性能問題。我們需要盡量減少Overdraw。



我們可以通過前面介紹的Monitor GPU Rendering來查看渲染的表現(xiàn)性能如何,另外也可以通過開發(fā)者選項(xiàng)里面的Show GPU view updates來查看視圖更新的操作,最后我們還可以通過HierarchyViewer這個(gè)工具來查看布局,使得布局盡量扁平化,移除非必需的UI組件,這些操作能夠減少M(fèi)easure,Layout的計(jì)算時(shí)間。
7)Overdraw, Cliprect, QuickReject

引起性能問題的一個(gè)很重要的方面是因?yàn)檫^多復(fù)雜的繪制操作。我們可以通過工具來檢測并修復(fù)標(biāo)準(zhǔn)UI組件的Overdraw問題,但是針對高度自定義的UI組件則顯得有些力不從心。

有一個(gè)竅門是我們可以通過執(zhí)行幾個(gè)APIs方法來顯著提升繪制操作的性能。前面有提到過,非可見的UI組件進(jìn)行繪制更新會導(dǎo)致Overdraw。例如Nav Drawer從前置可見的Activity滑出之后,如果還繼續(xù)繪制那些在Nav Drawer里面不可見的UI組件,這就導(dǎo)致了Overdraw。為了解決這個(gè)問題,Android系統(tǒng)會通過避免繪制那些完全不可見的組件來盡量減少Overdraw。那些Nav Drawer里面不可見的View就不會被執(zhí)行浪費(fèi)資源。



但是不幸的是,對于那些過于復(fù)雜的自定義的View(重寫了onDraw方法),Android系統(tǒng)無法檢測具體在onDraw里面會執(zhí)行什么操作,系統(tǒng)無法監(jiān)控并自動優(yōu)化,也就無法避免Overdraw了。但是我們可以通過canvas.clipRect()來幫助系統(tǒng)識別那些可見的區(qū)域。這個(gè)方法可以指定一塊矩形區(qū)域,只有在這個(gè)區(qū)域內(nèi)才會被繪制,其他的區(qū)域會被忽視。這個(gè)API可以很好的幫助那些有多組重疊組件的自定義View來控制顯示的區(qū)域。同時(shí)clipRect方法還可以幫助節(jié)約CPU與GPU資源,在clipRect區(qū)域之外的繪制指令都不會被執(zhí)行,那些部分內(nèi)容在矩形區(qū)域內(nèi)的組件,仍然會得到繪制。



除了clipRect方法之外,我們還可以使用canvas.quickreject()來判斷是否沒和某個(gè)矩形相交,從而跳過那些非矩形區(qū)域內(nèi)的繪制操作。做了那些優(yōu)化之后,我們可以通過上面介紹的Show GPU Overdraw來查看效果。
8)Memory Churn and performance

雖然Android有自動管理內(nèi)存的機(jī)制,但是對內(nèi)存的不恰當(dāng)使用仍然容易引起嚴(yán)重的性能問題。在同一幀里面創(chuàng)建過多的對象是件需要特別引起注意的事情。

Android系統(tǒng)里面有一個(gè)Generational Heap Memory的模型,系統(tǒng)會根據(jù)內(nèi)存中不同的內(nèi)存數(shù)據(jù)類型分別執(zhí)行不同的GC操作。例如,最近剛分配的對象會放在Young Generation區(qū)域,這個(gè)區(qū)域的對象通常都是會快速被創(chuàng)建并且很快被銷毀回收的,同時(shí)這個(gè)區(qū)域的GC操作速度也是比Old Generation區(qū)域的GC操作速度更快的。



除了速度差異之外,執(zhí)行GC操作的時(shí)候,任何線程的任何操作都會需要暫停,等待GC操作完成之后,其他操作才能夠繼續(xù)運(yùn)行。



通常來說,單個(gè)的GC并不會占用太多時(shí)間,但是大量不停的GC操作則會顯著占用幀間隔時(shí)間(16ms)。如果在幀間隔時(shí)間里面做了過多的GC操作,那么自然其他類似計(jì)算,渲染等操作的可用時(shí)間就變得少了。

導(dǎo)致GC頻繁執(zhí)行有兩個(gè)原因:

  • Memory Churn內(nèi)存抖動,內(nèi)存抖動是因?yàn)榇罅康膶ο蟊粍?chuàng)建又在短時(shí)間內(nèi)馬上被釋放。
  • 瞬間產(chǎn)生大量的對象會嚴(yán)重占用Young Generation的內(nèi)存區(qū)域,當(dāng)達(dá)到閥值,剩余空間不夠的時(shí)候,也會觸發(fā)GC。即使每次分配的對象占用了很少的內(nèi)存,但是他們疊加在一起會增加Heap的壓力,從而觸發(fā)更多其他類型的GC。這個(gè)操作有可能會影響到幀率,并使得用戶感知到性能問題。




解決上面的問題有簡潔直觀方法,如果你在Memory Monitor里面查看到短時(shí)間發(fā)生了多次內(nèi)存的漲跌,這意味著很有可能發(fā)生了內(nèi)存抖動。



同時(shí)我們還可以通過Allocation Tracker來查看在短時(shí)間內(nèi),同一個(gè)棧中不斷進(jìn)出的相同對象。這是內(nèi)存抖動的典型信號之一。

當(dāng)你大致定位問題之后,接下去的問題修復(fù)也就顯得相對直接簡單了。例如,你需要避免在for循環(huán)里面分配對象占用內(nèi)存,需要嘗試把對象的創(chuàng)建移到循環(huán)體之外,自定義View中的onDraw方法也需要引起注意,每次屏幕發(fā)生繪制以及動畫執(zhí)行過程中,onDraw方法都會被調(diào)用到,避免在onDraw方法里面執(zhí)行復(fù)雜的操作,避免創(chuàng)建對象。對于那些無法避免需要創(chuàng)建對象的情況,我們可以考慮對象池模型,通過對象池來解決頻繁創(chuàng)建與銷毀的問題,但是這里需要注意結(jié)束使用之后,需要手動釋放對象池中的對象。

來自:胡凱的博客
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android性能優(yōu)化典范
Android面試常問的技術(shù)問題
【新提醒】Unity項(xiàng)目中UI同學(xué)需知的程序相關(guān)要點(diǎn)
Android 開發(fā)者選項(xiàng)詳述
Andriod性能優(yōu)化之列表卡頓——以“簡書”APP為例
Android Monitor工具詳解大全
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服