Android性能優(yōu)化整理

高質(zhì)量的應(yīng)用目標:快、穩(wěn)、省、小

  • 快:使用時避免出現(xiàn)卡頓,響應(yīng)速度快,減少用戶等待的時間,滿足用戶期望。

  • 穩(wěn):減低 crash 率和 ANR 率,不要在用戶使用過程中崩潰和無響應(yīng)。

  • ?。汗?jié)省流量和耗電,減少用戶使用成本,避免使用時導(dǎo)致手機發(fā)燙。

  • ?。喊惭b包小可以降低用戶的安裝成本


1. 卡頓優(yōu)化

歸根結(jié)底:顯示問題

Android系統(tǒng)顯示原理

應(yīng)用層繪制好后,通過跨進程通信把需要的數(shù)據(jù)傳遞到系統(tǒng)層,通過系統(tǒng)層的SurfaceFlinger把數(shù)據(jù)渲染到顯示屏幕上,通過Android的刷新機制來刷新數(shù)據(jù)。

應(yīng)用層

  • View繪制核心步驟:Measure、Layout、Draw
  • 從 ViewRootImp類的performTraversals() 方法開始執(zhí)行,Measure和Layout都是通過遞歸來獲取View的大小和位置,并且以深度作為優(yōu)先級,層級越深、元素越多、耗時也就越長。

繪制方式

  • 軟件繪制(CPU)
  • 硬件加速(GPU,3.0后全面支持)

應(yīng)用層GPU繪制缺點:

  1. 耗電
    GPU功耗比CPU高

  2. 兼容問題
    某些接口和函數(shù)不支持硬件加速

  3. 內(nèi)存大
    使用OpenGL接口至少需要8MB內(nèi)存

繪制過程

  • CPU準備數(shù)據(jù),通過Driver層把數(shù)據(jù)交給CPU渲染
  • CPU主要負責(zé)Measure、Layout、Record、Execute的數(shù)據(jù)計算工作
    GPU負責(zé)柵格化(Rasterization)、渲染
  • 圖形API不允許CPU直接與GPU進行通信,通過圖形驅(qū)動層(Graphics Driver)來連接這兩部分
  • 圖形驅(qū)動層維護了一個隊列,CPU把display list 添加到隊列中,GPU從中取出數(shù)據(jù)進行繪制,最終顯示。

系統(tǒng)層

通過系統(tǒng)級進程中的SurfaceFlinger服務(wù)來真正把需要顯示的數(shù)據(jù)渲染到屏幕上

  • 響應(yīng)客戶端事件,創(chuàng)建Layer與客戶端的Surface建立連接。

  • 接收客戶端數(shù)據(jù)及屬性,修改Layer屬性,如尺寸、顏色、透明度等。

  • 將創(chuàng)建的Layer內(nèi)容刷新到屏幕上。

  • 維持Layer的序列,并對Layer最終輸出做出裁剪計算。

  • 應(yīng)用層繪制到緩存區(qū),SurfaceFlinger把緩存區(qū)數(shù)據(jù)渲染到屏幕,由于是不同的進程,所以使用Android的匿名共享內(nèi)存SharedClient緩存需要顯示的數(shù)據(jù)來達到目的。

  • FPS表示每秒傳遞的幀數(shù)。Android系統(tǒng)每隔16ms發(fā)出VSYNC信號,觸發(fā)對UI進行渲染。主要場景執(zhí)行動畫或滑動ListView。

  • CPU或GPU負載過重,布局過于復(fù)雜,16ms不能進行渲染,UI層疊太多,動畫執(zhí)行次數(shù)過多,刷新不及時等容易丟幀。


刷新機制

雙緩沖

Framebuffer帶來殘影問題

VSYNC(Vertical Synchronization)

CPU主動查詢保證數(shù)據(jù)是否準備好,效率低
定時中斷,收到信號,CPU處理各幀數(shù)據(jù)

Choreographer:起調(diào)度作用

收到VSYNC信號,調(diào)用用戶設(shè)置的回調(diào)函數(shù)

  • CALLBACK_INPUT : 輸入事件有關(guān)
  • CALLBACK_ANIMATION : 與動畫有關(guān)
  • CALLBACK_TRAVERSAL : UI控件繪制有關(guān)

卡頓根本原因

  1. 繪制任務(wù)太重,繪制一幀內(nèi)容耗時太長
  2. 主線程太忙,根據(jù)系統(tǒng)傳遞過來的VSYNC信號來時還沒準備好數(shù)據(jù)導(dǎo)致丟幀。

主線程主要做以下幾個方面工作

  • UI生命周期控制
  • 系統(tǒng)事件處理
  • 消息處理
  • 界面布局
  • 界面繪制
  • 界面刷新
  • 除此之外,應(yīng)該盡量避免將其他處理放在主線程中,特別復(fù)雜的數(shù)據(jù)計算和網(wǎng)絡(luò)請求等。

性能分析工具

1. Profile GPU Rendering

  • 一個圖形監(jiān)測工具,能實時反應(yīng)當(dāng)前繪制的耗時

  • 橫軸表示時間,縱軸表示每一幀的耗時

  • 隨著時間推移,從左到右的刷新呈現(xiàn)

  • 提供一個標準的耗時,如果高于標準耗時,就表示當(dāng)前這一幀丟失

  • 可以通過adb shell dumpsys gfxinfo com..把具體耗時輸出到日志來進行查看分析

2. TraceView

  • TraceView是Android SDK自帶的工具,用來分析函數(shù)調(diào)用過程,可以對Android的應(yīng)用程序以及Framework層的代碼進行性能分析。

  • 它是一個圖形化的工具,最終會產(chǎn)生一個圖表,用于對性能分析進行說明,可以分析到每一個方法的執(zhí)行時間,其中可以統(tǒng)計出該方法調(diào)用次數(shù)和遞歸次數(shù),實際時長等參數(shù)維度,使用非常直觀,分析性能非常方便。

3. Systrace

  • Systrace是Android 4.1及以上版本提供的性能數(shù)據(jù)采樣和分析工具,它是通過系統(tǒng)的角度來返回一些信息。

  • 它可以幫助開發(fā)者收集Android關(guān)鍵子系統(tǒng),如Surfaceflinger、WindowManagerService等Framework部分關(guān)鍵模塊、服務(wù)、View系統(tǒng)等運行信息,從而幫助開發(fā)者更直觀地分析系統(tǒng)瓶頸,改進性能。

  • Systrace的功能包括跟蹤系統(tǒng)的I/O操作、內(nèi)核工作隊列、CPU負載等,在UI顯示性能分析上提供很好的數(shù)據(jù),特別是在動畫播放不流暢、渲染卡等問題上。


卡頓優(yōu)化建議

1 布局優(yōu)化(HieracrchyViewer&Lint)

  • 減少層級。
  • 合理使用RelativeLayout和LinerLayout,合理使用Merge。
  • 提高顯示速度。
  • 使用ViewStub。
  • 布局復(fù)用。
  • 通過標簽來提高復(fù)用。
  • 盡可能少用wrap_content。
  • 增加布局measure時計算成本,在已知寬高為固定值時,不用wrap_content
  • 刪除控件中無用的屬性。

2 避免過度繪制

過度繪制
在屏幕上的某個像素在同一幀的時間內(nèi)被繪制了多次,從而浪費了多余的CPU以及GPU。

布局上的優(yōu)化:

  • 移除XML中非必須的背景
  • 移除Window默認的背景
  • 按需顯示占位背景圖片

自定義View優(yōu)化:
使用 canvas.clipRect()來幫助系統(tǒng)識別那些可見的區(qū)域,只有在這個區(qū)域內(nèi)才會被繪制。

開發(fā)者選項:調(diào)試GPU過度重繪

  • 無色:1
  • 藍色:1+
  • 綠色:2+
  • 淡紅:3+(不超過1/4屏可接受)
  • 深紅:4++(嚴重影響性能,需優(yōu)化)

3 啟動優(yōu)化

  • 通過對啟動速度的監(jiān)控,發(fā)現(xiàn)影響啟動速度的問題所在,優(yōu)化啟動邏輯,提高應(yīng)用的啟動速度。

  • 啟動主要完成三件事:
    UI布局
    繪制
    數(shù)據(jù)準備

  • UI布局。
    應(yīng)用一般都有閃屏頁,優(yōu)化閃屏頁的UI布局,可以通過Profile GPU Rendering檢測丟幀情況。使用HierarchyView檢查布局優(yōu)化

  • 啟動加載邏輯優(yōu)化。
    可以采用分布加載、異步加載、延期加載策略來提高應(yīng)用啟動速度。

  • 數(shù)據(jù)準備。
    數(shù)據(jù)初始化分析,加載數(shù)據(jù)可以考慮用線程初始化等策略。

4 合理的刷新機制

  • 頻繁刷新會增加資源開銷,并且可能導(dǎo)致卡頓發(fā)生,因此:

  • 盡量減少刷新次數(shù)。

  • 盡量避免后臺有高的CPU線程運行。

  • 縮小刷新區(qū)域。

5 提升動畫性能

  • 幀動畫:一組圖片按順序顯示。圖片過多,消耗資源,效果最差。

  • 補間動畫:只需要定義開始和結(jié)束關(guān)鍵幀,之間效果自動生成。
    局限性:
    只能用于View對象,只有繼承于View或View的控件;
    只有四種動畫:淡入淡出、縮放、平移、旋轉(zhuǎn)。
    只改變了顯示效果,沒有改變真正屬性。

  • 屬性動畫:可以應(yīng)用于View,和任何對象。持續(xù)時間、時間插值、重復(fù)次數(shù)行為、動畫系和、幀刷新延遲。相對于不見動畫,重繪少,性能更佳。

  • 在實現(xiàn)動畫效果時,需要根據(jù)不同場景選擇合適的動畫框架來實現(xiàn)。有些情況下,可以用硬件加速方式來提供流暢度。


2. 內(nèi)存優(yōu)化

Android內(nèi)存管理機制

  • Android應(yīng)用都是在 Android的虛擬機上運行,應(yīng)用程序的內(nèi)存分配與垃圾回收都是由虛擬機完成的。

  • 在Android系統(tǒng),虛擬機有兩種運行模式:Dalvik和ART。

工具1 Memory Monitor

Memory Monitor是一款使用非常簡單的圖形化工具,可以很好地監(jiān)控系統(tǒng)或應(yīng)用的內(nèi)存使用情況,主要有以下功能:

  • 顯示可用和已用內(nèi)存,并且以時間為維度實時反應(yīng)內(nèi)存分配和回收情況。
  • 快速判斷應(yīng)用程序的運行緩慢是否由于過度的內(nèi)存回收導(dǎo)致。
  • 快速判斷應(yīng)用是否由于內(nèi)存不足導(dǎo)致程序崩潰。

工具2 Heap Viewer

Heap Viewer的主要功能是查看不同數(shù)據(jù)類型在內(nèi)存中的使用情況,可以看到當(dāng)前進程中的Heap Size的情況,分別有哪些類型的數(shù)據(jù),以及各種類型數(shù)據(jù)占比情況。通過分析這些數(shù)據(jù)來找到大的內(nèi)存對象,再進一步分析這些大對象,進而通過優(yōu)化減少內(nèi)存開銷,也可以通過數(shù)據(jù)的變化發(fā)現(xiàn)內(nèi)存泄漏。

工具3 Allocation Tracker

Memory Monitor和Heap Viewer都可以很直觀且實時地監(jiān)控內(nèi)存使用情況,還能發(fā)現(xiàn)內(nèi)存問題,但發(fā)現(xiàn)內(nèi)存問題后不能再進一步找到原因,或者發(fā)現(xiàn)一塊異常內(nèi)存,但不能區(qū)別是否正常,同時在發(fā)現(xiàn)問題后,也不能定位到具體的類和方法。這時就需要使用另一個內(nèi)存分析工具Allocation Tracker,進行更詳細的分析,Allocation Tracker可以分配跟蹤記錄應(yīng)用程序的內(nèi)存分配,并列出了它們的調(diào)用堆棧,可以查看所有對象內(nèi)存分配的周期。

工具4 Memory Analyzer Tool(MAT)

MAT是一個快速,功能豐富的Java Heap分析工具,通過分析Java進程的內(nèi)存快照HPROF分析,從眾多的對象中分析,快速計算出在內(nèi)存中對象占用的大小,查看哪些對象不能被垃圾收集器回收,并可以通過視圖直觀地查看可能造成這種結(jié)果的對象。


常見內(nèi)存泄漏場景

  • 資源性對象未關(guān)閉。比如Cursor、File文件等,往往都用了一些緩沖,在不使用時,應(yīng)該及時關(guān)閉它們。

  • 注冊對象未注銷。比如事件注冊后未注銷,會導(dǎo)致觀察者列表中維持著對象的引用。

  • 類的靜態(tài)變量持有大數(shù)據(jù)對象。

  • 非靜態(tài)內(nèi)部類的靜態(tài)實例。

  • Handler臨時性內(nèi)存泄漏。如果Handler是非靜態(tài)的,容易導(dǎo)致Activity或Service不會被回收。

  • 容器中的對象沒清理造成的內(nèi)存泄漏。

  • WebView。WebView存在著內(nèi)存泄漏的問題,在應(yīng)用中只要使用一次WebView,內(nèi)存就不會被釋放掉。


LeakCanary 第三方開源庫

這是一個檢測內(nèi)存泄漏的開源庫,可以在發(fā)生內(nèi)存泄漏時告警,并且生成leak tarce分析泄漏位置,同時可以提供Dump文件進行分析。


優(yōu)化內(nèi)存空間

  • 對象引用。
    強引用、軟引用、弱引用、虛引用四種引用類型,根據(jù)業(yè)務(wù)需求合理使用不同,選擇不同的引用類型。

  • 減少不必要的內(nèi)存開銷。
    注意自動裝箱,增加內(nèi)存復(fù)用,比如有效利用系統(tǒng)自帶的資源、視圖復(fù)用、對象池、Bitmap對象的復(fù)用。

  • 使用最優(yōu)的數(shù)據(jù)類型。
    比如針對數(shù)據(jù)類容器結(jié)構(gòu),可以使用ArrayMap數(shù)據(jù)結(jié)構(gòu),避免使用枚舉類型,使用緩存Lrucache等等。

  • 圖片內(nèi)存優(yōu)化。
    可以設(shè)置位圖規(guī)格,根據(jù)采樣因子做壓縮,用一些圖片緩存方式對圖片進行管理等等。


3. 穩(wěn)定性優(yōu)化

  • 提高代碼質(zhì)量。比如開發(fā)期間的代碼審核,看些代碼設(shè)計邏輯,業(yè)務(wù)合理性等。

  • 代碼靜態(tài)掃描工具。常見工具有Android Lint、Findbugs、Checkstyle、PMD等等。

  • Crash監(jiān)控。把一些崩潰的信息,異常信息及時地記錄下來,以便后續(xù)分析解決。

  • Crash上傳機制。在Crash后,盡量先保存日志到本地,然后等下一次網(wǎng)絡(luò)正常時再上傳日志信息。


4. 耗電優(yōu)化

  • 5.0之后專門引入了一個獲取設(shè)備上電量消耗信息的API:Battery Historian。一款由Google提供的Android系統(tǒng)電量圖形化數(shù)據(jù)分析工具,直觀地展示出手機的電量消耗過程,通過輸入電量分析文件,顯示消耗情況,最后提供一些可供參考電量優(yōu)化的方法。

  • 計算優(yōu)化,避開浮點運算等。

  • 避免WakeLock使用不當(dāng)。
    休眠意味著CPU頻率降低,需要做一些需要大量運算的任務(wù)時,所以需要喚醒CPU

  • 使用JobScheduler

--

5. 安裝包大小瘦身

  • 代碼混淆。
    使用ProGuard代碼混淆器工具,它包括壓縮、優(yōu)化、混淆等功能。
  • 資源優(yōu)化。
    比如使用Android Lint刪除冗余資源,資源文件最少化等。
  • 圖片優(yōu)化。
    比如利用AAPT工具對PNG格式的圖片做壓縮處理,降低圖片色彩位數(shù)等。
  • 避免重復(fù)功能的庫,使用WebP圖片格式等。
  • 插件化。
    比如功能模塊放在服務(wù)器上,按需下載,可以減少安裝包大小。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容