讓你的App飛起來

jopen 9年前發布 | 10K 次閱讀 移動開發 APP
 

本文將介紹優化Android App的N種方法和N種工具。

###信條

  • 用數據說話:在細微的差別面前大部分人無法感知辨別,在每一次優化代碼后使用如下將介紹的工具進行檢驗。
  • 使用低性能機器測試:低性能的機器會更多地暴露問題。
  • 意識到等價交換的思想:所有優良代碼之上的優化都是基于等價交換,而這其中基本上都是以空間換時間。

###Systrace

Systrace是大多數開發者不去使用的工具,因為大家不知道如何使用它提供的數據。Systrace 的功能包括跟蹤系統的 I/O 操作、內核工作隊列、CPU 負載以及 Android 各個子系統的運行狀況等。

它有三部分組成:

  • 內核部分:Systrace 利用了Linux Kernel 中的 ftrace 功能。所以,如果要使用 Systrace 的話,必須開啟 kernel 中和 ftrace 相關的模塊。
  • 數據采集部分:Android 定義了一個 Trace 類。應用程序可利用該類把統計信息輸出給 ftrace。同時,Android 還有一個 atrace 程序,它可以從 ftrace 中讀取統計信息然后交給數據分析工具來處理。
  • 數據分析工具:Android 提供一個 systrace.py(python腳本文件,位于Android SDK 目錄 /tools/systrace 中,其內部將調用 atrace 程序)用來配置數據采集的方式(如采集數據的標簽、輸出文件名等)和收集 ftrace 統計數據并生成一個結果網頁文件供用戶查看。

Systrace使用方式 有兩種:

  • 1.Device Monitor
  • 2.命令行
    $ cd android-sdk/platform-tools/systrace $ python systrace.py --set-tags=gfx,view,wm $ adb shell stop $ adb shell start 

ps:先在設備中打開Settings > Developer options > Monitoring > Enable traces。

抓取的信息使用瀏覽器打開如下:

讓你的App飛起來

我們來選取一個Alert來看一下:

讓你的App飛起來

可以看到Alert原因是Long View#draw(),下面還會有相關文檔鏈接。選擇Frame這一行,就能看到每一幀的渲染,通過不同的顏色發現一些問題,我們來選擇紅色的一幀:

讓你的App飛起來

在底部,有三個Alert信息,打開“Inflation during ListView recycling”:

讓你的App飛起來

看這部分耗費的時間,32ms,超過了保證60fps的16ms。再看下面細分每一步耗費的時間,有5個obtainView都消耗了大約 5ms。Description指出了問題所在,沒有使用ListView的復用機制造成inflate單個Item成本過高。再看上面的圖形部分,它將 所有的東西都可視化,我們放大來看“inflate”:

讓你的App飛起來

在選擇一幀之后,可以通過“m”鍵顯示具體耗費的時間。可以看到耗費超過19ms渲染這一幀。展開這一幀唯一的一個Alert,看到“Scheduling delay”。選擇最長的DrawFrame來看一下:

讓你的App飛起來

Wall duration是從時間片的開始到結束。CPU Duration是CPU的實際運行時間。注意這兩個時間的巨大差別,來看一下CPU這段時間做了什么:

讓你的App飛起來

四個核心都處于忙碌狀態,選擇一個Thread看它從哪里發起,一個包名為com.udinic.keepbusyapp。原來是其它app的原 因。這種情況通常是暫時的,因為其它app不太可能在后臺長時間占用CPU,這些線程可能來自你的App的其它進程,或者是主進程。由于Systrace 是以系統的角度返回一些信息,要進一步獲取CPU滿負荷運行的原因,我們來使用另一個工具Traceview。

###TraceviewTraceview是一個很好的性能分析工具。它可以通過圖形化的方式讓我們了解我們要跟蹤的程序的性能,并且能具體到method:

讓你的App飛起來

使用方式同樣有兩種,Android Device Monitor或者使用代碼,參考 這里 .

我們來看一下不同列代表的含義:

  • Name:method的名稱,前面有一個和上圖對應的顏色標識。
  • Inclusive CPU Time:此方法和子方法調用占用的CPU時間。
  • Exclusive CPU Time:此方法單獨調用占用的CPU時間。
  • Inclusive / Exclusive Real Time:從方法開始到結束的時間,類似于“Wall Duration“。
  • Calls+Recursion:調用次數。
  • CPU/Real time per Call:每次調用平均占用的CPU時間。

我打開了一個不能平滑滾動的App,開始跟蹤,滾動以下部分,停止跟蹤。找到getView()方法,展開:

讓你的App飛起來

這個方法調用了12次,每次CPU時間3ms,但是每次調用的真實時間是162ms,絕對有問題!

查看這個方法下地Children,Thread.join()耗費了約98%的inclusive real time。這個方法是用來等待其他線程結束。另一個children是Thread.start(),由此認定getView()方法啟動了一個線程并等 待它結束。

但是這個線程在哪?

我們不知道這個getView()中的線程做了什么,因為getView()中沒有直接啟動它。為了找到它,我查找了Thread.start()方法。最終發現了它:

讓你的App飛起來

經過作者 Udi Cohen 同意,本文內容參考引用了 Speed up your app

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!