1、前言
隨著項(xiàng)目版本的迭代,App的性能問題會(huì)逐漸暴露出來,而好的用戶體驗(yàn)與性能表現(xiàn)緊密相關(guān),性能問題從應(yīng)用的啟動(dòng)優(yōu)化開始,下面會(huì)根據(jù)實(shí)際app性能測(cè)試案例,進(jìn)行app性能評(píng)測(cè)之啟動(dòng)時(shí)間的分析和總結(jié)。
2、App啟動(dòng)方式了解
通常來說, 一個(gè)App啟動(dòng)也會(huì)分如下三中不同的狀態(tài):
-
冷啟動(dòng)
當(dāng)啟動(dòng)應(yīng)用時(shí),后臺(tái)沒有該應(yīng)用的進(jìn)程,這時(shí)系統(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給該應(yīng)用,這個(gè)啟動(dòng)方式就是冷啟動(dòng),也就是先實(shí)例化Application冷啟動(dòng)的流程即為App啟動(dòng)流程的全過程, 需要?jiǎng)?chuàng)建App進(jìn)程, 加載相關(guān)資源, 啟動(dòng)Main Thread, 初始化首屏Activity等.
在這個(gè)過程中, 屏幕會(huì)顯示一個(gè)空白的窗口(顏色基于主題), 直至首屏Activity完全啟動(dòng).
下圖展示了冷啟動(dòng)的時(shí)間線:
冷啟動(dòng)流程.png
-
熱啟動(dòng)
當(dāng)啟動(dòng)應(yīng)用時(shí),后臺(tái)已有該應(yīng)用的進(jìn)程,這時(shí)會(huì)從已有的進(jìn)程來啟動(dòng)Activity(不需要重新創(chuàng)建Application)類同與冷啟動(dòng), 在這個(gè)過程中, 屏幕會(huì)顯示一個(gè)空白的窗口(顏色基于主題), 直至activity渲染完畢.
-
溫啟動(dòng)
介于冷啟動(dòng)和熱啟動(dòng)之間, 一般來說在以下兩種情況下發(fā)生:用戶back退出了App, 然后又啟動(dòng). App進(jìn)程可能還在運(yùn)行, 但是activity需要重建.
用戶退出App后, 系統(tǒng)可能由于內(nèi)存原因?qū)pp殺死, 進(jìn)程和activity都需要重啟, 但是可以在onCreate中將被動(dòng)殺死鎖保存的狀態(tài)(saved instance state)恢復(fù).
通過三種啟動(dòng)狀態(tài)的相關(guān)描述, 可以看出我們要做的啟動(dòng)優(yōu)化其實(shí)就是針對(duì)冷啟動(dòng). 熱啟動(dòng)和溫啟動(dòng)都相對(duì)較快.
3、性能評(píng)測(cè)結(jié)果案例分析
3.1 XX銀行 APP啟動(dòng)時(shí)間評(píng)測(cè)結(jié)果分析
3.1.1 啟動(dòng)時(shí)間測(cè)試結(jié)果
統(tǒng)計(jì)的時(shí)間為APP的冷啟動(dòng)時(shí)間,4G網(wǎng)絡(luò)情況下,平均冷啟動(dòng)時(shí)間為14.1S,平均熱啟動(dòng)時(shí)間為6.7S,無(wú)網(wǎng)絡(luò)時(shí)平均啟動(dòng)時(shí)間為5.2S。由于APP的啟動(dòng)時(shí)間耗時(shí)遠(yuǎn)遠(yuǎn)超過行業(yè)標(biāo)準(zhǔn)水平3S,當(dāng)app啟動(dòng)時(shí),任何一個(gè)地方有耗時(shí)操作都會(huì)拖慢我們應(yīng)用的啟動(dòng)速度,所以針對(duì)APP啟動(dòng)時(shí)間做了具體分析
3.1.2評(píng)測(cè)結(jié)果分析
首先來看App從點(diǎn)擊桌面圖標(biāo)到我們看到App的主界面整個(gè)過程中經(jīng)過了哪些步驟:
啟動(dòng)虛擬機(jī)—>啟動(dòng)AMS —>通過Zygote創(chuàng)建ApplicationProcess進(jìn)程–>Application的構(gòu)造器方法——>attachBaseContext()——>onCreate()——>Activity的構(gòu)造方法——>onCreate()——>配置主題中背景等屬性——>onStart()——>onResume()——>測(cè)量布局繪制顯示在界面上。
1)初始化Application
- 【初始化Application】應(yīng)用程序初始化總共耗費(fèi)了3.26S,耗時(shí)已超過行業(yè)APP啟動(dòng)標(biāo)準(zhǔn)基線時(shí)間3S。具體看下耗時(shí)詳情分析:
(1)應(yīng)用Application.attach的時(shí)間較長(zhǎng)。應(yīng)用存在多個(gè)dex文件,請(qǐng)控制應(yīng)用方法數(shù)量。
(2)onCreate方法耗時(shí)長(zhǎng),主要體現(xiàn)BaseApplication創(chuàng)建上。
長(zhǎng)耗時(shí)方法排名如下:
1.com.pingan.fstandard.framework.base.BaseApplication.onCreate(BaseApplication.java)
- com.pingan.fstandard.common.c.a(InitManager.java)
- com.pafinancialtech.pafs.kitchendaddy.f.b(PAFFToast.java:83
4.com.pingan.fstandard.HomeApplication.d(HomeApplication.java:51
綜上分析,BaseApplication創(chuàng)建上耗費(fèi)較長(zhǎng)時(shí)間,需要開發(fā)進(jìn)行更詳細(xì)的分析優(yōu)化。另外,初始化Application時(shí),也包含了任意門相關(guān)等非核心功能的程序,建議啟動(dòng)時(shí)不創(chuàng)建該類程序。
2)初始化Activity
- 【初始化Activity】耗時(shí)也過長(zhǎng),耗時(shí)約1s左右
主要耗時(shí)的地方是在閃屏界面創(chuàng)建oncreate時(shí)com.pingan.fstandard.activity.SplashActivity.onCreate,建議開發(fā)優(yōu)化
3)加載請(qǐng)求及響應(yīng)
首先來一張流程圖了解一下我們APP首頁(yè)加載的一個(gè)流程
- 【網(wǎng)絡(luò)請(qǐng)求及響應(yīng)】總體來看,首頁(yè)加載耗時(shí)占比最多,需要6s左右,對(duì)應(yīng)的網(wǎng)絡(luò)消耗時(shí)間占比45%左右。
根據(jù)抓包及代碼段分析顯示APP啟動(dòng)到首頁(yè)加載完成是一個(gè)預(yù)加載和異步加載的過程。
(1) 項(xiàng)目中大部分第三方組件都搶占先機(jī),在Application主線程初始化。這樣的初始化方式肯定是過重的,建議考慮異步初始化三方組件,不阻塞主線程;延遲部分三方組件(比如埋點(diǎn)統(tǒng)計(jì)、任意門、ImageLoader的初始化)。
(2) 啟動(dòng)到首頁(yè)加載完成網(wǎng)絡(luò)請(qǐng)求密集,請(qǐng)求內(nèi)容豐富,部分資源重復(fù)請(qǐng)求。
請(qǐng)求了相關(guān)配置信息、啟動(dòng)頁(yè)廣告、個(gè)推、磁貼配置信息、商城理財(cái)產(chǎn)品列表,運(yùn)營(yíng)廣告Banner、F后端接口,廣告BANNER位、插件信息、任意門、百度地圖SDK(talkingdata、灰度升級(jí))等林林總總加起來就有40+個(gè)網(wǎng)絡(luò)請(qǐng)求,加載的數(shù)據(jù)+廣告頁(yè)一共有1.7M左右,這說明了我們的APP首頁(yè)設(shè)計(jì)的內(nèi)容比較豐富,部分資源重復(fù)請(qǐng)求,部分內(nèi)容需要調(diào)外部接口,所以耗時(shí)比較長(zhǎng),這是產(chǎn)品設(shè)計(jì)問題、信息未做緩存處理和部分外部關(guān)聯(lián)方接口響應(yīng)慢的原因?qū)е拢ㄗh優(yōu)化。
(3)非核心功能資源過早請(qǐng)求加載
另外其中類似百度地圖SDK、任意門、微信sdk相關(guān)插件只有在生活頁(yè)\分享時(shí)使用到的非主要業(yè)務(wù)功能啟動(dòng)時(shí)也加載出來了,建議開發(fā)同學(xué)和產(chǎn)品同學(xué)調(diào)整APP啟動(dòng)時(shí)網(wǎng)絡(luò)請(qǐng)求的加載策略,非核心/主要/高PV的功能相關(guān)的API,SDK、插件等沒有必要在啟動(dòng)時(shí)做加載緩存,這是非常耗時(shí)且得不償失的。
3.1.3啟動(dòng)時(shí)間優(yōu)化建議
(1)應(yīng)用Application.attach的時(shí)間較長(zhǎng)。應(yīng)用存在多個(gè)dex文件,請(qǐng)控制應(yīng)用方法數(shù)量。
(2)onCreate方法耗時(shí)長(zhǎng),主要體現(xiàn)BaseApplication創(chuàng)建上,需要開發(fā)進(jìn)行更詳細(xì)的分析優(yōu)化,建議考慮異步初始化三方組件,不阻塞主線程;延遲或者和產(chǎn)品一起梳理需要的去除的部分三方組件(比如統(tǒng)計(jì)、任意門、ImageLoader的初始化)。
(3)com.pingan.fstandard.activity.MainActivity存在過度繪制導(dǎo)致卡頓,首頁(yè)UI布局層次過多,建議開發(fā)進(jìn)一步分析優(yōu)化
(4)建議產(chǎn)品調(diào)整優(yōu)化app啟動(dòng)時(shí)網(wǎng)絡(luò)請(qǐng)求的加載策略,非核心/主要/高PV的功能相關(guān)的API,SDK、插件等沒有必要在啟動(dòng)時(shí)做加載緩存
(5)部分資源重復(fù)請(qǐng)求,建議信息緩存,常用信息只在第一次獲取,之后從緩存中取
(6)建議開發(fā)梳理無(wú)用但被執(zhí)行的老代碼,去掉無(wú)用但被執(zhí)行的老代碼
綜上,建議開發(fā)童鞋盡快投入做APP啟動(dòng)時(shí)性能改善和優(yōu)化,以提升行業(yè)相比競(jìng)品的競(jìng)爭(zhēng)力。
4、App端啟動(dòng)耗時(shí)排查方法及思路
4.1 排查方法:使用Traceview分析
TraceView 是 Android SDK 中內(nèi)置的1個(gè)工具,它可以加載 trace 文件,用圖形的情勢(shì)展現(xiàn)代碼的履行時(shí)間、次數(shù)及調(diào)用棧,便于我們分析。
(1)使用Android Studio工具DDMS
生成Traceview 進(jìn)行分析查看具體Trace期間各方法調(diào)用關(guān)系,調(diào)用次數(shù)以及耗時(shí)比例
(2)使用代碼生成 trace 文件
Debug.startMethodTracing("shixintrace");
//開始 trace,保存文件到 "/sdcard/shixintrace.trace"
// ...
Debug.stopMethodTracing(); //結(jié)束
代碼很簡(jiǎn)單,當(dāng)你調(diào)用開始代碼的時(shí)候,系統(tǒng)會(huì)生產(chǎn) trace 文件,并且產(chǎn)生追蹤數(shù)據(jù),當(dāng)你調(diào)用結(jié)束代碼時(shí),會(huì)將追蹤數(shù)據(jù)寫入到 trace 文件中。
下1步使用 adb 命令將 trace 文件導(dǎo)出到電腦:
adb pull /sdcard/shixintrace.trace /tmp
使用代碼生成 trace 方式的好處是容易控制追蹤的開始和結(jié)束,缺點(diǎn)就是步驟略微多了一點(diǎn)。
(3)直接使用android studio生成trace文件
Android Studio 內(nèi)置的 Android Monitor 可以很方便的生成 trace 文件到電腦。
注意:此方法僅僅適用于下拉代碼到本地生成DEBUG測(cè)試包到手機(jī)進(jìn)行調(diào)試
分析指標(biāo):
不應(yīng)在Application以及Activity的生命周期回調(diào)中做任何費(fèi)時(shí)操作,具體指標(biāo)大概是你在onCreate,onResume,onStart等回調(diào)中所花費(fèi)的總時(shí)間最好不要超過400ms,否則用戶在桌面點(diǎn)擊你的應(yīng)用圖標(biāo)后,將感覺到明顯的卡頓。
4.2 開啟嚴(yán)苛模式(StrictMode)
檢查是否有主線程做了耗時(shí)操作: 開啟 嚴(yán)苛模式(StrictMode)
(1)StrictMode可以用于捕捉發(fā)生在應(yīng)用程序 主線程中耗時(shí)的磁盤、網(wǎng)絡(luò)訪問或函數(shù)調(diào)用,使主線程處理UI和動(dòng)畫在磁盤讀寫和網(wǎng)絡(luò)操作時(shí)變得更平滑,避免主線程被阻塞,導(dǎo)致ANR窗口的發(fā)生。
下面是啟用StrictMode的實(shí)例,可以在Application的OnCreate中添加,這樣就能在程序啟動(dòng)的最初一刻進(jìn)行監(jiān)控了。
private void setStrictMode() {
if (Integer.valueOf(Build.VERSION.SDK) > 3) {
Log.d(LOG_TAG, "Enabling StrictMode policy over Sample application");
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll() // 這里可以替換為.detectDiskReads().detectDiskWrites().detectNetwork()。
// detectAll() 包括了磁盤讀寫和網(wǎng)絡(luò)I/O
.penaltyLog() //打印logcat,當(dāng)然也可以定位到dropbox,通過文件保存相應(yīng)的log
.penaltyDeath()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
}
}
(2)除了通過日志查看之外,我們也可以在開發(fā)者選項(xiàng)中開啟嚴(yán)格模式,開啟之后,如果主線程中有執(zhí)行時(shí)間長(zhǎng)的操作,屏幕則會(huì)閃爍,這是一個(gè)更加直接的方法。
4.3、通過抓包工具分析
可以通過抓包工具Charels、Fiddler等查看網(wǎng)絡(luò)請(qǐng)求加載了哪些資源,加載資源的順序、哪些資源重復(fù)加載、信息是否緩存
4.4、查看Logcat
通過adb輸出log信息,過濾日志查看APP啟動(dòng)時(shí)每個(gè)方法的大致耗時(shí)。
4.5、啟動(dòng)時(shí)間排查思路
對(duì)于App來說, 我們可以控制的啟動(dòng)時(shí)間線的點(diǎn)無(wú)外乎:
Application的onCreate
首屏Activity的渲染
而我們現(xiàn)在的App動(dòng)不動(dòng)集成了很多第三方服務(wù), 啟動(dòng)時(shí)需要檢查廣告, 注冊(cè)狀態(tài)等等一系列接口都是在Application的onCreate或是首屏的onCreate中做的.
5、啟動(dòng)時(shí)間耗時(shí)常見原因及優(yōu)化建議
5.1、 常見主要問題(持續(xù)補(bǔ)充ing)
- 部分?jǐn)?shù)據(jù)庫(kù)及IO的操作發(fā)生在首屏Activity主線程;
- Application中創(chuàng)建了線程池;
- 啟動(dòng)時(shí)做密集沉重的初始化(Heavy app initialization);
- Multidex的使用,也是拖慢啟動(dòng)速度的元兇;
- UI存在過度繪制;
- 首屏Activity網(wǎng)絡(luò)請(qǐng)求密集;
- 非核心功能資源過早請(qǐng)求加載
- 工作線程使用未設(shè)置優(yōu)先級(jí);
- 信息未緩存,重復(fù)獲取同樣信息;
- 流程問題:例如閃屏圖每次下載,當(dāng)次使用;
- 執(zhí)行無(wú)用老代碼;
- 執(zhí)行開發(fā)階段使用的代碼;
- 執(zhí)行重復(fù)邏輯;
- 調(diào)用三方SDK里或者Demo里的多余代碼;
5.2、建議:
- 去掉無(wú)用但被執(zhí)行的老代碼;
- 去掉開發(fā)階段使用但線上被執(zhí)行的代碼;
- 去掉重復(fù)邏輯執(zhí)行代碼;
- UI渲染優(yōu)化,去除重復(fù)繪制,減少UI重復(fù)繪制時(shí)間
- 去掉調(diào)用三方SDK里或者Demo里的多余代碼;
- 信息緩存,常用信息只在第一次獲取,之后從緩存中取;
- 項(xiàng)目是多進(jìn)程架構(gòu),只在主進(jìn)程執(zhí)行Application的onCreate();
- 根據(jù)優(yōu)先級(jí)的劃分,一些初始化工作能否將任務(wù)優(yōu)先級(jí)劃分成3個(gè)等級(jí),任務(wù)優(yōu)先級(jí)為2,3的,通過懶加載的方式在首頁(yè)渲染完成后進(jìn)行加載
- 避免I/O操作、反序列化、網(wǎng)絡(luò)操作、布局嵌套等。
參考文獻(xiàn):
學(xué)習(xí)地址:
https://www.cnblogs.com/sunzn/p/3192231.html
http://www.wfuyu.com/technology/27625.html
http://blog.csdn.net/qq_16131393/article/details/51172488