系統啟動過程:
1)開機打開電源
2)BootLoader程序
3)Linux的 init.rc
- init進程
5)Zygote的JVM
6)SystemServer進程
Binder線程池
SystemServiceManager(AMS、WMS、PMS、CameraService等等被啟動)
1)啟動頁白屏及黑屏解決?
2)啟動太慢怎么解決?
3)怎么保證應用啟動不卡頓?
4)App啟動崩潰異常捕捉
5)統計啟動時長,標準
App啟動速度是用戶的第一印象,本章會介紹精準度量啟動速度的方式,啟動優化的相關工具、常規優化手段等,同時我會介紹異步初始化以及延遲初始化的最優解,以最優雅、可維護性高的的方式獲得閃電般的啟動速度。...
一. App 啟動優化介紹
App Startup time
冷啟動:耗時最多、衡量標準。
啟動App、加載空白Window、創建進程
隨后任務,創建Application、啟動主線程、創建MainActivity。
熱啟動:后臺 ——> 前臺。最快
溫啟動:較快。僅僅重走LifeCycle。
優化方向:
Application和Activity生命周期
二. 啟動時間測量方式
兩種方式:adb 命令 / 手動打點
adb方式
adb shell am start -W packagename/首屏Activity
ThisTime:最后一個Activity啟動耗時
TotalTime:所有Activity啟動耗時
WaitTime:AMS啟動Activity的總耗時
(此方式線下使用方便,不能帶到線上。非嚴謹、精確時間)手動打點:
啟動時埋點,啟動結束時埋點,兩者差值。
寫個工具類,讀取SystemCurrentTimeMillis
結束時間的記錄位置?真實數據展示出來,Feed第一條展示。
onWindowFocusChanged不夠準確。
getViewTreeObserver 的 addOnPreDrawListener
三. 啟動優化工具選擇
主要兩個工具:TraceView、Systrace
1. TraceView
圖形的形式展現執行時間、調用等。信息全面,包含所有線程
使用方式:Debug.startMethodTracing("");
Debug.stopMethodTracing("");
生成文件在sd卡:Android/data/packagename/files
最大能有 8MB的信息。
圖像分析:
Top Down:Self Time、Total Time (Wall Clock Time、Thread Time)是call Chart 的詳細文字版本
Call Chart:a調用b,那么a 就在 b 的上面。系統API 橙色、應用自己的綠色,第三放的就是藍色
Flame Chart:相同調用順序的過程會合并在一起。
BottomUp:和Top Down相反。
TraceView 運行時開銷嚴重,整體都會變慢。
與CpuProfiler相比,此工具Android Studio中直接使用。可能需要手速很快才能獲取到。
2.Systrace
結合Android 內核的數據,生成一個Html報告
API 18 以上使用,推薦TraceCompact
使用方式:
python systrace.py -t 10 [other-options] [categories]
https://developer.android.com/studio/command-line/systrace#command_options
查看CPU 核心運行狀況
UIThread 和 Other Threads的對比
通過Slice 查看 start 、wall Duration(代碼執行時間)、CPU Duration (代碼消耗cpu的時間)
舉例:鎖沖突
四. 優雅獲取方法耗時講解
常規方法的侵入性太強。重復編輯。
所以,采用AOP方法(Aspect Oriented Programming 面向切面編程)
- 針對同一類問題的統一處理
- 無侵入添加代碼
AspectJ使用:
classPath ‘com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0’
implementation 'org.aspectj:aspectjrt:1.8.+'
apply plugin: 'android-aspectjx'
Join Points:程序運行時的執行點,可以作為切面的地方。
- 函數調用、執行
- 獲取、設置變量
- 類初始化
PointCut:帶條件的JoinPoints (篩選一下某些點)
一種Hook,要插入代碼的位置
Before:PointCut之前執行。Advice,具體插入位置。
After:PointCut之后執行
Around:PointCut之前和之后分別執行
execution:處理Join Point 的類型,call、execution
(* android.app.Activity.on**(..)):匹配規則
onActivityCalled:要插入的代碼
4.1優雅獲取方法耗時實操
4.2 異步優化詳解
優化技巧:
Theme切換:感覺上的快。
異步優化:
子線程分擔住線程任務,并行減少時間。
ExecutorService service = Executors.newFixedThreadPool(CORE_POOL_SIZE);
service.submit(new Runnable(){
public void run(){
方法分別放入;
}
});
不符合異步要求的。部分代碼必須運行在主線程當中,那么放棄這種異步優化的方案。
需要在某階段完成。由于異步執行不知道 子任務何時結束,跳轉新界面時 該方法是否完成,
添加
private CountDownLatch mCountDownLatch = new CountDownLatch(1); // 一個簡單的開/關鎖存器
在條件被滿足后
mCountDownLatch.countDown();
try {
mCountDownLatch.await();
} catch(InterruptedException e){
e.printStackTrace;
}
4.3 異步初始化最優解-啟動器-1
充分利用CPU多核,自動梳理執行順序
- 代碼Task化,啟動邏輯抽象為Task。
- 根據所有任務以來關系排序生成一個有向無環圖
- 多線程按照排序后的優先級依次執行
4.4 異步初始化最優解-啟動器-2
TaskDispatcher。并向當中要執行的Task 分別繼承,在run方法中進行執行。
4.5 更優秀的延遲初始化方案
常規方式,回調方法中執行耗時。很有可能導致feed 卡頓。
對延遲任務進行分批初始化。
- 利用IdleHandler特性,空閑時執行
4.6 啟動優化其它方案
異步、延遲、懶加載。
技術、業務相結合。
cpu time才是優化方向
按照systrace 及 cpu time 跑滿cpu
IO密集型 和 CPU密集型 操作。
收斂啟動代碼修改權限。
結合Ci修改啟動代碼需要Review通知
其他方案:
- 提前加載SharedPreferences。getSharedPreference load到內存中。如果沒有完成一直阻塞進行等待。
- Multidex之前加載,利用此階段CPU覆寫 getApplicationContext() 返回 this。 attachBaseContext中
啟動階段不啟動子進程,子進程會共享CPU資源,導致主進程CPU緊張。注意啟動順序:App onCreate 之前是ContentProvider
類加載優化:提前異步加載(可以替換掉系統的ClassLoader,每個類加載的時候都打印一個Log)Class.forName() 只加載類本身及其靜態變量的引用類。
new 類實例 可以額外加載類成員變量的引用類
啟動階段抑制GC
- CPU鎖頻
啟動速度模擬面試
1)你做啟動優化是怎么做的?
- 分析現狀、確認問題。(目前啟動流程復雜,主線程執行了太多的代碼)
- 針對性優化(實現異步初始化)簡單異步 指向了啟動器。
- 長期保持優化效果。
2)是怎么異步的,異步遇到問題沒有?
- 異步演進過程
- 詳細介紹啟動器
3)有哪些容易忽略的點?
- cpu time 和 wall time。
- 注意延遲初始化的優化
- 介紹黑科技,類加載。Systrace 可能沒有給滿的CPU,拉高CPU。
4)版本迭代導致的啟動變慢有好的解決方式嗎?
- 啟動器
- 結合CI
- 監控完善