文章目錄:
- 什么是性能測試
- 為什么要做性能測試
- App性能測試指標是什么
- 如何使用Profiler工具進行性能測試——以結對編程作業為例
- 關於App性能優化的一些建議
1. 什么是性能測試
性能測試針對系統的性能指標,建立性能測試模型,制定性能測試方案,制定監控策略,在場景條件之下執行性能場景,分析判斷性能瓶頸並調優,最終得出性能結果來評估系統的性能指標是否滿足既定值。
2. 為什么要做性能測試
1)目前絕大多數應用都是基於網絡的分布式應用,我們無法知道用戶數量,用戶場景的不確定性,導致系統測試時,不僅僅是功能,業務邏輯,接口測試,還要測試系統性能。一個用戶沒問題,但是用戶一旦多了就可能出現各種各樣的問題,所以需要進行系統性能測試。
2)用戶數量增加,系統負載增加,進行系統性能測試,知道系統承受的並發用戶數量,帶寬是否夠用,cpu是否夠用,內存是否夠用,硬盤速度是否跟得上。從服務端來看,測試服務器是否能承載用戶多並發,系統是否穩定,從用戶角度看響應時間速度。
3. App性能測試指標是什么
- APP啟動速度(啟動時間)
- CPU的占用量
- 電量消耗
- 內存占用
- FPS(每秒傳輸幀率)直接反應APP流暢度
- 流量
- CPU過度渲染
在Profiler里,主要的性能指標有:cpu占用、內存占用、流量、電量消耗。由於我的app不涉及聯網功能,我們將重點圍繞cpu、內存展開測試。
4. 如何使用Profiler工具進行性能測試
4.1 Profiler使用流程
打開Android studio,選擇結對編程的項目,點擊界面右上角的速度表圖標或者左下角的Profiler圖標,彈出Profiler工具界面,如下圖所示



現在我們沒有運行虛擬機,也沒有讀取捕獲的片段,所以界面是空的。
現在單擊運行按鈕,啟動虛擬機並運行我們的app。可以看到,進程被自動加載到了profiler當中。左邊是我們正在運行的進程,右邊是實時的性能數據。我們可以清楚地看到虛擬機的實時運行情況。

界面中繪制了四張曲線圖,分別對應CPU(處理器)、Memory(內存)、Network(網絡)、Energy(耗電)四個指標,想要查看某個指標的具體信息,只需要點擊曲線圖即可。
下面介紹不同性能指標工具的詳細使用。
4.2 CPU分析工具(CPU Profiler)
進入Cpu Profiler,我們可以看到如下界面。

它會立即開始顯示應用程序的CPU使用率和線程的活動
CPU Profiler的默認視圖包含以下內容:
①:Event timeline:顯示應用在他們的生命周期中不同狀態間轉換時的活動,並指示用戶與設備的交互,包括屏幕旋轉事件
②:CPU timeline:顯示應用程序的實時CPU使用情況(占可用CPU總時間的百分比)以及應用程序正在使用的線程總數。時間表還顯示了其他進程(如系統進程或其他應用程序)的CPU使用情況,因此您可以將其與應用程序的使用情況進行比較。可以通過沿着時間軸的橫軸移動鼠標來檢查歷史CPU使用率數據。
③:Thread activity timeline:列出屬於你的應用程序進程的每個線程,並使用下面列出的顏色在時間線上指示其活動。記錄方法跟蹤之后,可以從此時間線中選擇一個線程,以在跟蹤窗格中檢查其數據。
綠色:線程處於活動狀態或准備好使用CPU。也就是說,它處於“運行”或“可運行”狀態。
黃色:線程處於活動狀態,但它正在等待I / O操作(例如磁盤或網絡I / O),然后才能完成工作。
灰色:線程正在休眠,不占用任何CPU時間。當線程需要訪問尚不可用的資源時,有時會發生這種情況。線程進入自願睡眠,或者內核使線程進入休眠狀態,直到需要的資源變為可用。
④:Recording configurations:允許您選擇以下選項之一來確定探查器如何記錄方法跟蹤。
Sampled(采樣):一個默認配置,可以在應用程序執行期間頻繁地捕獲應用程序的調用堆棧。分析器比較捕獲的數據集合以獲取關於應用代碼執行的時間和資源使用信息。基於抽樣的跟蹤的一個固有問題是,如果您的應用程序在捕獲調用堆棧之后輸入方法,並在下次捕獲之前退出該方法,則該方法調用不會被分析器記錄。如果您對如此短的生命周期跟蹤方法感興趣,則應使用檢測跟蹤。
Instrumented:默認配置,在運行時測試您的應用程序,以在每個方法調用的開始和結束時記錄一個時間戳。收集時間戳並進行比較,以生成方法跟蹤數據,包括定時信息和CPU使用情況。請注意,與每種方法相關的開銷都會影響運行時性能,並可能影響分析數據 - 對於生命周期相對較短的方法來說,這一點更為明顯。此外,如果您的應用程序在很短的時間內執行大量方法,分析器可能會快速超出其文件大小限制,並且無法記錄任何進一步的跟蹤數據。
Edit configurations:允許您更改上述采樣和檢測記錄配置的某些默認設置,並將其保存為自定義配置。
⑤:Record button:開始和停止錄制方法跟蹤按鈕
記錄和檢查方法跟蹤
對於應用程序進程中的每個線程,你可以找到在一段時間內執行哪些方法以及每個方法在執行期間消耗的CPU資源。你還可以使用方法跟蹤來識別調用者和被調用者,調用者是一種調用另一種方法的方法,被調用方是另一種方法調用的方法。你可以使用此信息來確定哪些方法太頻繁地調用特定資源繁重的任務,就可以嘗試優化應用程序的代碼以避免不必要的工作。
要開始記錄方法跟蹤,從下拉菜單中選擇Sampled或Instrumented類型,然后單擊Record開始進行記錄,完成后點擊Stop recording停止記錄。profiler自動選擇記錄的時間幀,並在方法跟蹤窗格中顯示它的跟蹤信息,如下圖所示。如果要檢查不同線程的方法跟蹤,只需從線程活動時間軸中選擇它。

app生成1000道題的記錄情況如下:

點擊線程左邊的小三角可以查看詳細信息。
主線程的信息如下:

點擊方法對應的長條還會顯示方法的具體信息。長方形越長代表方法耗時越久。

4.3 內存分析工具(Memory Profiler)
可以通過左上角的下拉菜單切換不同的工具。我們選擇Memory。

默認顯示的界面如下:

內存剖析器的默認視圖包括以下內容:
①:強制執行垃圾收集事件的按鈕
②:捕獲堆轉儲的按鈕
③:一個記錄內存分配的按鈕,當連接到運行Android7.1或更低的設備時,該按鈕才會出現
④:放大/退出時間線按鈕
⑤:可以跳轉到實時內存數據的按鈕。
⑥:事件時間軸,顯示活動狀態、用戶輸入事件和屏幕旋轉事件。
⑦:內存使用時間線,包括以下內容:一個堆疊圖,顯示每個內存類別的內存大小,如左側的y軸和頂部的顏色鍵。虛線表示已分配對象的數量,如右側的y軸所示。每個垃圾收集事件的圖標
內存計算指標
左上角能看到一欄數據,顯示了不同的內存計算指標。

它們分別代表以下內容:
Java:從Java或Kotlin代碼中分配的對象的內存
Native:從C或c++代碼中分配的對象的內存,即使你沒有在app中使用c++,你可能會看到一些本地內存,因為Android框架使用Native內存來處理各種任務,比如處理圖像資產和其他圖形——即使你寫的代碼是Java或Kotlin
Graphics:用於圖形緩沖區隊列的內存用於顯示屏幕上的像素,包括GL表面、GL紋理等。(注意,這是與CPU共享的內存,而不是專用的GPU內存)
Stack:在你的應用程序中,Native和Java棧使用的內存。這通常與你的應用程序運行的線程數有關
Code:您的應用程序用於代碼和資源的內存,如dex字節碼,優化或編譯的dex代碼。所以庫和字體
Other:應用程序使用的內存,系統不確定如何分類
Allocated:應用程序分配的Java/Kotlin對象的數量。這並不計算用C或c++分配的對象
記錄某一時刻的內存分配情況
如果我們想要記錄app在某段時間的內存占用情況,應該怎么做呢。
方法很簡單。選擇左邊錄制選項中的Record Java/Kotlin allocations,點擊Record,工具便開始記錄內存占用情況。

需要結束錄制時,點擊紅色圓圈即可。

隨后錄制結果便會被保存,你可以在左側菜單中找到它,點擊便可查看記錄的數據。

以生成題目的過程為例,記錄的內存占用如下:

或者你也可以以可視化圖形的方式展現內存占用情況,我個人更加喜歡這種方式。

將鼠標懸停在彩色長方形上,我們可以很清楚地看到不同的類占用的內存大小,長方形越長,內存占用越大。
以我的app為例,我可以看到,在我自己編寫的類中,GeneratorFragment占用了最多的內存。以此為依據,我們便可以針對性地優化個別模塊。
5.關於App性能優化的一些建議
除了利用性能測試工具分析應用性能,尋找優化空間,開發者在開發過程中,就應該注意一些性能優化技巧,養成良好的開發習慣,減輕性能優化的負擔。
下面是一些優化建議:
-
在LinearLayout和RelativeLayout都可以完成布局的情況下優先選擇LinearLayout,可以減少View的層級,但是注意相同組件可能RelativeLayout繪制時間長 -
onDraw中不要創建新的局部對象,onDraw方法中不要做耗時的任務。 -
不要在主線程進行網絡訪問/大文件的IO操作。 -
繪制UI時,盡量減少繪制UI層次;減少不必要的view嵌套。 -
當我們的布局是用的FrameLayout的時候,我們可以把它改成merge,可以避免自己的幀布局和系統的ContentFrameLayout幀布局重疊造成重復計算(measure和layout)。 -
在view層級相同的情況下,盡量使用 LinerLayout而不是RelativeLayout;因為RelativeLayout在測量的時候會測量二次,而LinerLayout測量一次,可以看下它們的源碼。 -
刪除控件中無用的屬性。 -
布局復用.比如listView 布局復用。 -
盡量避免過度繪制(overdraw),比如:背景經常容易造成過度繪制。由於我們布局設置了背景,同時用到的MaterialDesign的主題會默認給一個背景。這時應該把主題添加的背景去掉;還有移除XML 中非必須的背景。 -
自定義View優化。使用 canvas.clipRect()來幫助系統識別那些可見的區域,只有在這個區域內才會被繪制。也是避免過度繪制。 -
啟動優化,啟動速度的監控,發現影響啟動速度的問題所在,優化啟動邏輯,提高應用的啟動速度。比如閃屏頁面,合理優化布局,加載邏輯優化,數據准備。 -
合理的刷新機制,盡量減少刷新次數,盡量避免后台有高的 CPU 線程運行,縮小刷新區域。
