都9102年了,Android 冷啓動優化還是隻會老三樣嗎

圖:Benjamin Suter

性能優化一直都是一個 Android 開發者逃不過的話題,啓動優化則更是重中之重。啓動速度可以直接影響一個 App 的留存率和轉化率,沒有人會希望自己點擊之後還要等一會纔打開。

但是當我一番調研後發現,網上大部分啓動優化相關的文章,套路都差不多,我稱之爲老三樣。

什麼是老三樣?

  1. 將啓動頁主題背景設置成閃屏頁圖片

這麼做的目的主要是爲了消除啓動時的黑白屏,給用戶一種秒響應的感覺,但是並不會真正減少用戶啓動時間,僅屬於視覺優化。

  1. 主頁面佈局優化

1)通過減少冗餘或者嵌套佈局來降低視圖層次結構
2)用 ViewStub 替代在啓動過程中不需要顯示的 UI 控件

  1. Application 和 主 Activity 的 onCreate 中異步初始化某些代碼

因爲在主線程上進行資源初始化會降低啓動速度,所以可以將不必要的資源初始化延遲,達到優化的效果。但是這裏要注意懶加載集中化的問題,別用戶啓動時間快了,但是無法在界面上操作就尷尬了。

老三樣並不說是不管用或者過時了,只是這三種優化方式都是非常基礎的方式,當你的啓動優化遇到了瓶頸,是不能夠再通過這三種方式突破的。

而且只會基礎的優化方式,並不會在履歷中展現出優勢。

所以今天說說在老三樣的基礎優化之上還有哪些可行的方案。


進階方案一 通過 systrace 查找耗時代碼

具體步驟

1)清空手機後臺

2)在命令行執行

python $ANDROID_HOME/platform-tools/systrace/systrace.py gfx view wm am pm ss dalvik app sched -b 90960 -a 你的包名  -o test.log.html

這一步需要你係統環境配置了 ANDROID_HOME 環境變量。

3)運行你的App,正常操作到你想測性能的地方,然後再命令行窗口中按 Enter 鍵停止收集

4)用 chrome(只支持此瀏覽器)打開生成的 test.log.html 結果文件,打開效果如下圖:


目前需要關心地方就是我們的應用進程相關的,也就是紅框圈起來的地方。

圖中的 F 代表繪製幀,黃色/紅色表示該幀繪製超時,綠色代表繪製正常,也就是在16.6ms內繪製完一幀。

關於 systrace 如何使用可以參考這篇文章 性能工具Systrace

放大可以看到在啓動過程中,控件渲染耗時情況


所以可以很容易發現哪些啓動過程中沒有用到的 UI 控件也被渲染了,這時就可以用 ViewStub 去替代。

但是現在可以看到的都是系統調用的耗時情況,因爲谷歌預先在代碼裏關鍵的地方加上了監控,如果想要看到自己方法的耗時,

那需要手動在方法入口加上 Trace.beginSection("TAG")

在方法結束的地方加上Trace.endSection()

這樣就可以在生成的結果中看到我們自定義的 tag。

如果很多地方你都想加上監控,手動加是肯定不合適的,這裏推薦函數插樁方式自動加上監控代碼,參考 systrace+函數插樁

這種方式不僅可以幫助監控啓動過程中性能問題,再做卡頓優化的時候也可以用這種方式。

定位到了耗時方法,再做一些針對性的優化就相對容易了。


進階方案二 通過 redex 重排列 class 文件

redex 是 Facebook 開源的一款字節碼優化工具,目前只支持 mac 和 linux。

我們用的是裏面的 interdex 功能來重排列我們 dex 中的 class 文件,那麼爲什麼重排列 class 文件可以優化啓動速度?

簡單的說,通過文件重排列的目的,就是將啓動階段需要用到的文件在 APK 文件中排布在一起,儘可能的利用 Linux 文件系統的 pagecache 機制,用最少的磁盤 IO 次數,讀取儘可能多的啓動階段需要的文件,減少 IO 開銷,從而達到提升啓動性能的目的

具體可以參考支付寶的這篇 《通過安裝包重排布優化 Android 端啓動性能》

所以我們着手要做的就三件事:

1)安裝配置 redex
2)獲得啓動過程中 class 文件的加載順序
3)根據這個順序重排列 dex 中的 class 文件

具體步驟

1)下載 redex,配置環境(Mac OS)

git clone https://github.com/facebook/redex.git

xcode-select --install

brew install autoconf automake libtool python3

brew install boost jsoncpp

2)編譯安裝 redex

cd redex

autoreconf -ivf && ./configure && make

sudo make install

編譯時間較久,不想幹等着,可以加上 say 指令,編譯完成後語音通知

autoreconf -ivf && ./configure && make && say '編譯完成'

3)配置優化項

因爲 redex 默認不開啓 interdex,所以我們要在配置文件中加上相應的配置,在 redex 文檔中有說明

所以我們打開配置文件

cd redex/config/
vi default.config

按照下圖配置


4)獲得啓動 class 加載順序列表

這裏按照 redex 提供的工具獲取,但是需要手機有 root 權限

首先清空後臺進程,然後打開你的應用

獲取你的應用的 pid

adb shell ps | grep 你的應用包名

收集堆內存,需要 root 權限

adb root
adb shell am dumpheap YOUR_PID /data/local/tmp/SOMEDUMP.hprof

把堆內存文件拉取到電腦的某個位置

adb pull /data/local/tmp/SOMEDUMP.hprof YOUR_DIR_HERE/.

通過 python 腳本解析堆內存,生成類加載順序列表

python redex/tools/hprof/dump_classes_from_hprof.py --hprof YOUR_DIR_HERE/SOMEDUMP.hprof > list_of_classes.txt

ps: 這個腳本支持 Python 2,執行過程中如果遇到某個庫沒安裝之類的,直接通過 pip install 缺失的庫 就可以

5)通過 redex 處理

ANDROID_SDK=你的Android sdk路徑 redex input.apk -o output.apk

6)重新簽名

這時候生成的 output.apk 是不能直接安裝的,需要重新簽名,我測試用的是 debug 包,所以重新簽了debug 的簽名

jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android output.apk androiddebugkey

到這就可以重新安裝測試了,按照 facebook 的說法和一些大廠的實踐,啓動速度大概可以提高 10%~20%,在低端機型上效果應該更明顯。

關於 redex 的使用和相關配置文檔,都可以在 redex/docs/ 目錄下查看。

其他相關

啓動耗時測量

爲了正確診斷冷啓動的性能,需要冷啓動的時間指標,下面有兩種簡單的方式:

adb命令adb shell am start -S -W 包名/啓動類的全名

例如:

adb shell am start -S -W com.android.helloword/com.android.helloword.MainActivity


  • ThisTime : 最後一個 Activity 的啓動耗時(例如從 LaunchActivity - >MainActivity「adb命令輸入的Activity」 , 只統計 MainActivity 的啓動耗時)
  • TotalTime : 啓動一連串的 Activity 總耗時.(有幾個Activity 就統計幾個)
  • WaitTime : 應用進程的創建過程 + TotalTime

這裏我們關注 TotalTime 就可以。

谷歌在 Android4.4(API 19)上也提供了測量方法,在 logcat 中過濾 Displayed 字段


輸出的值表示在啓動過程和完成在屏幕上繪製相應 Activity 之間經過的時間,其實和上面的方式得到的結果是一樣的。

關於 Android App 的冷啓動過程和一些概念可以參考谷歌官方文檔 「App startup time 」

由於一些原因,還有一些優化方法沒有實踐,有興趣的可以自行了解:

1)啓動過程中的 GC 優化,儘量減少 GC 次數,避免大量或者頻繁創建對象,如必須,可嘗試放到 Native 實現

2)線程優化,儘可能減少 cpu 調度,具體就是控制線程數量和調度

3)在類加載的過程中通過 Hook 去掉類驗證的過程,可以在 systrace 生成的文件中看到 verifyClass 過程,因爲需要校驗方法的每一個指令,所以是一個比較耗時的操作

以上就是我關於 Android 冷啓動優化的一些總結,水平有限,難免出現不準確的地方,歡迎指正​。​

本文首發於公衆號「後知後jue」,微信搜索關注回覆「1024」,你懂的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章