檢測和解決Android應用的效能問題

開發技術前線發表於2015-07-28

前言

無論你的應用多麼有創新性、有用,如果它卡得要命,或者非常消耗記憶體,那麼每人將會願意使用它。

因此,效能變得尤為重要。當你忙碌於構建精美的使用者介面或者完成新的特性時,你可能容易忘卻掉一些效能相關的事情。

這也是為什麼有Google Play的應用稽核機制的原因之一。

這篇文章中,你會看到每個Android工程師需要了解的一些效能問題。你將會學會使用Android SDK提供的、已安裝在你的裝置中的工具來測試這些問題是否發生在你自己的應用中。

如果在你的應用中發現了一個效能問題,你肯定會想修復它。我們還會看一看如何使用Android SDK 工具來獲取更多關於那些沒有覆蓋到的效能問題的相關資訊。一旦你有了這些資訊,你將會對如何提升應用效能有一個更深刻的理解,並且能夠構建出讓使用者喜愛的App。

過度繪製

步驟1 : 問題描述

你應用的使用者介面是連線使用者的紐帶,但是建立漂亮的介面只是挑戰的其中一面,你還需要確保使用者介面流暢的執行。

一個常見的問題就是使用者介面卡頓,出現這種情況的原因可能是overdraw。Overdraw是螢幕上的某個畫素在同一幀的時間內被繪製了多次。

例如,想象一下一個有藍色的背景文字,Android不僅會繪製對使用者可見的藍色區域,而是會繪製整個藍色的背景以及上面的文字。這意味著一些畫素會被兩次繪製,這就是過度繪製。

一些如上述例子所說的過度繪製示例是不可避免的。然而,過多的多度繪製會引發明顯的效能問題,因此你必須將過度繪製的可能性降到最小。

檢測應用中的過度繪製相對來說比較簡單。大量的過度繪製會引出其他使用者介面相關問題,例如檢視層級過於複雜等。基於這些原因,當你測試你的App的效能問題時,從過度繪製開始是一個明智的選擇。

步驟2 : 檢測過度繪製

好訊息是你的Android裝置上已經內建了檢測過度繪製的工具。

因此你需要做的第一步就是安裝你要測試的App到你的裝置中。然後開啟設定頁面,選擇開發選項(Developer Options)->除錯GPU 過度繪製(Debug GPU Overdraw),然後選擇“顯示過度繪製區域(Show overdraw area)”。如下圖所示。

On your device select Settings Developer Options Debug GPU Overdraw Show overdraw area

這個工具使用色塊來代表不同數量的過度繪製。剩下的事情就是啟動你要測試的應用,然後觀察它的過度繪製情況。

Launch your app and check the amount of overdraw

  • 沒顏色 : 沒有過度繪製,也就是說一個畫素只被繪製了一次。
  • 藍色 : 過度繪製了一次,也就是一個畫素點被繪製了兩次。
  • 綠色 : 過度繪製了2次. 也就是一個畫素點被繪製了三次,通常,你需要集中精力優化過度繪製次數大於等於2次的情況。
  • 淺紅色 : 過度繪製3次。這取決於你的應用,小範圍的3次過度繪製可能是不可避免的,但是如果你看到了中等或者大量的紅色區域那麼你就需要查詢出現這個問題的原因了。
  • 深紅色 : 過度繪製4次,畫素點被繪製了5次,甚至更多次。出現這種問題你絕逼要找到原因,並且解決它。

步驟3 : 最小化過度繪製

一旦你發現了某個區域有嚴重的過度繪製,最簡單的方法就是開啟你應用的xml檔案找到過度重疊的區域,特別是那些不可見的drawable物件和被繪製在其他控制元件上的背景,以此來降低這些地方的過度繪製。

你也應該查詢那些背景屬性設定為白色,並且它的父檢視背景也設定為白色的區域。所有這些都會引起嚴重的過度繪製。

Android系統能自動的降低一些簡單的過度繪製,但是這些對於複雜的自定義View並沒有什麼價值,因為Android不會知道你如何繪製你的內容。

如果你在App中使用了複雜的自定義View,你可以為使用clipRect函式為你的檢視定義可繪製區域的邊界。更新相關資訊可以參考official Android documentation.

## 2. Android 圖形渲染

步驟1 : 問題描述

另一個常見的效能問題就是應用的檢視層級。為了渲染每個檢視,Android都會經歷這三個階段 :

  1. 測量
  2. 佈局
  3. 繪製

花在這三個階段的時間與View層級中的View的數量成正比,這就意味著降低App渲染時間的最簡單的方法就是識別和移除那些並沒有什麼卵用的UI元素。

即使在你的檢視層級上的所有View都是必須的,不同的佈局方式也可能對測量過程產生重要的影響。通常來說,你的檢視層級越深,花在測量檢視的時間就越長。

在檢視渲染期間,每個View都要向它的父View提供它自己的尺寸。如果父view發現了任意一個尺寸問題,那麼它會強制要求所有的子檢視重新測量。

即使沒有錯誤發生,重新測量也可能出現。例如,為了正確的進行佈局RelativeLayout通常會對它們的子檢視進行兩次測量。子檢視使用了layout_weight屬性的LinearLayout也會對它的子檢視進行兩次測量。

這些都取決於你的佈局方式,測量和重新測量的代價非常昂貴,它會嚴重影響你的渲染速度。

確保你的使用者介面渲染流暢的關鍵就是移除任何非必須的View以及減少你的View層級。

Hierarchy Viewer是一個能夠將你完整的View層級視覺化的工具,這個工具能夠幫助你發現冗餘的View以及巢狀的佈局。

步驟2:使用 Hierarchy Viewer

在我們進一步瞭解Hierarchy Viewer之前,你需要知道它的一些規則。首先Hierarchy Viewer只能與正在執行的App進行互動,而不是你的原始碼。這就是說你需要將App安裝到你的裝置或者模擬器上。

還有一個最重要的問題,就是預設情況下Hierarchy Viewer只能與執行開發版Android系統的裝置進行互動(譯者注: 一般來說,使用模擬器即可)。如果你沒有開發裝置,那你需要新增ViewServeclass到你的應用中。

瞭解這些之後就讓我們開啟Android Studio,並且選擇”tools” -> “Android” -> “Android Device Monitor”,如圖所示。

然後點選Hierarchy View按鈕,如下圖所示。

螢幕左邊的Windows標籤下列出了所有Android裝置和模擬器。選擇你的裝置後,你會看到你裝置上執行的所有程式。選中你要檢測的程式,然後你會看到三個自動更新的檢視層級區域。

這三個視窗提供了檢視層級的三個不同視覺化展示。

  • Tree View: **** 檢視層級視窗,每個節點代表了一個View;
  • Tree Overview: 整個檢視層級的縮略佈局;
  • Layout View: 當前檢視層級的輪廓.

Hierarchy View中有三個視窗。如果你在一個視窗中選擇了一個View,那麼它會在另外兩個中高亮顯示。你能同時使用這三個視窗查詢View層級中的冗餘檢視。

如果你不確定一個View是否是UI介面中的必須元素,最簡單的方法就是到Tree View視窗點選這個節點。你將會看到該View是如何顯示在螢幕的預覽,此時你就可以確切地知道該View是否是必須的。

但是即使一個View對最終的渲染效果有貢獻也並不意味著它不會引起嚴重的效能問題。你已經看到了如何通過Hierarchy Viewer來找到明顯的巢狀佈局,但是如果這引起的效能問題並不那麼明顯呢?或者還有其他的原因使得該檢視渲染得非常慢?

好訊息就是你還可以通過Hierarchy Viewer來剖析每個View在不同的渲染階段的耗時。當效能問題的原因不那麼明顯時,這是你發現問題的另一途徑。

下個章節我將為你展示如何通過Hierarchy Viewer來剖析每個View的渲染時間來找到潛伏在問題表面的效能問題。

步驟3 : 節點的效能分析

定位你的使用者介面瓶頸的最簡單方法就是收集每個View分別完成測量、佈局、繪製的時間。

你不僅可以通過Hierarchy Viewer收集這些資訊,Hierarchy Viewer還可以通俗易懂地向你展示這些資料,因此你可以通過這種形式來找到效能問題。

Hierarchy Viewer預設並不會顯示渲染時間。你需要到Tree View視窗新增這個資訊,然後選擇你想要測試的根節點。下一步,在Hierarchy Viewer上點選由綠、紅、紫的三個圓形色塊組成的按鈕,如圖所示。

三個圓點色塊就會顯示在每個節點上,從左到右,這些圓點分別代表 :

  • 用於測量的時間
  • 用於佈局的時間
  • 用於繪製的時間

每個圓點都有顏色 :

  • 綠色 代表該View的渲染速度至少要快於一半以上的其他參與測試的節點。例如,一個在佈局位置上的綠色的圓點代表它的佈局速度要快於50%以上的其他節點;
  • 黃色 代表該View慢於50%以上的其他節點;
  • 紅色 代表該View的渲染速度比其他所有參與測試的節點都慢。

當收集了這些資料之後,你不僅知道哪些View需要優化,你還會確切地知道是在渲染的哪個階段導致的問題。

哪些黃色、紅色的地方就是你需要開始優化的地方,這些效能指標與該檢視層級下的其他剖析節點也有關係。換句話說,你肯定會有一些檢視渲染得比其他的慢。

在開始改良你的View相關的程式碼之前,摸著你的良心問一句該View渲染得比其他檢視慢是否有一個合理的原因,如果答案是否定的,那麼就開始你的View優化之旅吧。

3. Memory Leaks 記憶體洩漏

步驟1:問題描述

Android是一個自動管理記憶體的開發環境,不要讓這個句話矇蔽了,因為記憶體洩漏依舊是可能發生的。這是因為垃圾回收器只會移除那些不可達的物件。如果它不是一個不可達的物件,那麼該物件就不會被釋放掉。

這些不可達的物件陰魂不散,聚集在你的堆記憶體中,佔用App的記憶體控制元件。如果你繼續洩漏物件,那麼可用的記憶體空間將會越來越小,GC操作就會頻繁觸發。

有兩個原因表明這是一個壞訊息。首先,GC操作通常不會明顯地影響你的App效能,但是當記憶體控制元件較小時大量的GC操作會使你的App變慢,此時UI就不會那麼流暢了。第二問題是移動裝置的記憶體空間相對來說較小,因此記憶體洩漏會快速地升級為記憶體溢位,導致應用Crash。

記憶體洩漏難以被檢測出。可能只有當使用者開始抱怨你的應用時你才能發覺記憶體洩漏問題。幸運地是,Android SDK提供了一些有用的工具來讓你找到這些問題。(譯者注 : Square的開源庫LeakCanary是查詢記憶體洩漏的優秀工具,強烈建議大家使用)。

步驟2 : 記憶體監視器 (Memory Monitor)

Memory Monitor是一個能夠實時獲取應用記憶體使用情況的工具。需要注意的是這個工具只能作用於正在執行的應用,因此確保你的要測試的應用已經安裝到你的裝置中,並且你的裝置已經連線到你的電腦上。

Memory Monitor已經內建在Android Studio中,因此你可以點選Android Studio的底部的”Memory”這個tab來切換到記憶體監視頁面。當你切換到該頁面的時候,Memory Monitor就開始記錄你的記憶體使用情況了。

如果Memory Monitor沒有開始記錄,那麼確保你的裝置是已經被選中的狀態。

如果Memory Monitor提示No debuggable applications,那麼你可以開啟Android Studio的”Tools”選單,選擇”Android”,然後確保選中了Enable adb integration。這個功能還不是很穩定,所以有時候你需要手動切換它的狀態。你也可以斷開裝置與電腦的連線,然後再重連,這樣可能就OK了。

一旦Memory Monitor檢測到正在執行的應用,它就會顯示這個應用的記憶體使用情況。已使用的記憶體會被表示為深藍色,未分配的記憶體則會變為淺藍色。

花一些時間與你的裝置互動,並且關注你的記憶體使用情況。最終已分配的記憶體會增長,直到沒有記憶體可用。此時,系統就會釋放觸發GC釋放記憶體,當你看到已分配的記憶體明顯的下降時就代表GC操作被觸發了。

GC通常情況下會將無用的記憶體釋放掉,但是當你看到App在短時間內快速增長或者GC變得非常頻繁,此時你就需要倍加小心了,這就是發生記憶體洩漏的訊號!

如果你通過Memory Monitor來追蹤一個可疑的記憶體洩漏問題,你可能會看到Android系統會為你的App增大可用記憶體,TODO : 。

最終,你可能會看到你的App消耗了非常多的記憶體以至於系統無法再給你的應用更多的可用記憶體。如果你看到這種場景,那麼說明你在記憶體使用上犯了很嚴重的錯誤。

步驟3 : Android Device Monitor

另一個能夠幫助你收集更新關於記憶體洩漏資訊和其他記憶體相關問題的工具是Android Device Monitor的DDMMS工具下的Heap。

Heap工具能夠通過顯示系統為你分配了多少記憶體來幫助你診斷記憶體洩漏問題。正如上面提到的,如果已分配的記憶體不斷地增長,那麼這是發生記憶體洩漏的明顯訊號。

但是這個工具還提供了許多關於你的應用堆記憶體使用情況的資料,包含你的App內分配的各種物件、分配的物件數量以及這些物件佔用了多少空間。這些額外的資訊對於你追蹤記憶體洩漏極為有用。

你可以在Android Device Monitor工具中選擇DDMS,在Devices中選擇你要檢測的App。然後選擇Heap標籤,如圖所示。然後花一些時間與你的App進行互動以收集記憶體資訊。

heap輸出資訊會在GC事件之後,因為你可以手動點選Cause GC來觸發GC,使得Heap記憶體資料儘快地顯示出來。

一旦GC事件被觸發了,heap標籤下就會更新App的堆記憶體使用資訊,這些資訊會在每次GC時更新。

## 總結

在這篇文章中,我們學習了一些開發中最常見的效能問題,過度繪製、記憶體洩漏、緩慢的UI渲染。

相信你已經掌握瞭如何使用工具來檢查這些問題,以及如何獲取更新的資訊來判斷你的應用中是否出現了這些效能問題。你有越多的資訊,就越容易追蹤到問題的原因並且修復它。

Android SDK有很多工具可以供你診斷和定位效能問題。如果你想學習更多這方面的知識,你可以訪問u這兩篇官方文件 Traceview and dmtracedump和 Allocation Tracker.

相關文章