愛奇藝Android客戶端啟動優化與分析
1、簡介
網際網路領域裡有個八秒定律,如果網頁開啟時間超過8秒,便會有超過70%的使用者放棄等待,對Android APP而言,要求更加嚴格,如果系統無響應時間超過5秒,便會出現ANR,APP可能會被強制關閉,因此,啟動時間作為一個重要的效能指標,關係著使用者的第一體驗。
愛奇藝安卓APP非常重視啟動速度的優化,本文將從啟動過程,啟動時間測量,啟動優化,以及後續監控等方面分享我們在啟動優化方面積累的經驗。
2 啟動模式
要準確的測量APP的啟動時間,首先我們要了解APP整個啟動過程。 啟動過程,一般可以分為以下三類:
從上圖可以看出,啟動過程中,Cold的模式下,生命週期中做的事情最多,啟動的時間最長,因此,我們以冷啟動來衡量APP啟動時間。啟動過程中,如何判斷哪些生命週期影響啟動速度呢?
3、啟動過程
我們知道,APP的啟動和執行,就是Linux系統建立程式和元件物件,並在UI執行緒中處理元件訊息的過程。
啟動過程圖:
App的啟動過程,可以劃分為三個階段:
3.1 建立程式
當APP啟動時,如果當前app的程式不存在,便會建立新的程式;App主程式啟動後,如果啟動某個元件,並且該元件設定了android:process屬性,元件所執行的程式不存在,也會建立新的程式。
需要注意的是,如果在啟動階段,初始化的元件中,包含了多個程式,便會建立多次程式,BindApplication操作也會重複執行多次
3.2 建立UI執行緒及Handler
程式建立後,會通過反射,執行ActivityThread入口函式,建立Handler,並在當前執行緒中prepareMainLooper,並在Handler中接收元件的訊息,我們來看一下Handler中處理的訊息:
-
LAUNCH_ACTIVITY,啟動,執行Activity
-
RESUME_ACTIVITY,恢復Activity
-
BIND_APPLICATION,啟動app
-
BIND_SERVICE,Service建立, onBind
-
LOW_MEMORY,記憶體不足,回收後臺程式
sMainThreadHandler中,處理的訊息很多,這裡只羅列了,可能在啟動階段可能會執行的操作, 這些操作都是執行在Main Thread中,對啟動而言,屬於阻塞性的。
Activity生命週期,自然需要在啟動階段執行,但,對於Service的建立,Trim_memory回撥,廣播接收等操作,就需要重點考慮,其操作耗時性。
3.3 Activity執行及繪製
前兩個過程,建立程式和UI執行緒及Handler,都是由系統決定的,對APP開發者而言,並不能控制其執行時間,在本階段,執行BindApplication,和Acitivity生命週期,都是可以由開發者自定義。
Activity執行到onResume之後,會執行至ViewRootImpl,執行兩次performTraversals,第二次traversal操作中,會執行performDraw操作,同時通知RenderThread執行緒執行繪製.
從啟動的三個階段,我們可以看出,啟動啟動時間的長短,決定因素在於,主執行緒中所做事情消耗的時間的多少,所以,我們的優化工作主要集中在,排查主執行緒中耗時性的工作,並進行合理的優化。Android手機,系統的資源是有限的,過多的非同步執行緒,會搶佔CPU,導致主執行緒執行時間片間隔增大。同樣的,記憶體消耗狀態,GC頻率,也會影響啟動的時間。
4、分析及測量
通過上述的原始碼的解讀,我們已經瞭解了啟動過程,以及可能引起啟動過慢的原因。接下來介紹一些常用的分析手段及時間測量方法。
啟動分析工具,主要使用SysTrace,具體的使用方法,請參考官網文件https://developer.android.com/studio/command-line/systrace。
4.1 SysTrace分析技巧
4.1.1 UI Thread 顏色顯示
-
綠色:Running
-
白色:Sleeping
-
棕色:Uninterruptible Sleep
-
橙色:Uninterruptible Sleep - Block I/O
其中10ms以內的,較短時間的Sleeping狀態,不用關注,可能是由於CPU排程的時間片分配間隔引起的;較長時間的Block I/O和Sleep狀態,可以確定有阻塞啟動的邏輯在這個階段執行,需要進一步對程式碼進行分析定位。
4.1.2 檢視CPU狀態及執行緒執行時長
檢視CPU佔用狀態:
執行緒執行:
通過該階段密集程度,反映出CPU佔用率,也能在一定程度上反映出該階段執行時間被阻塞情況;執行緒執行情況統計,可以檢視執行緒執行時間排名,對執行時間較長的子執行緒進行優化。
4.2 SysTrace啟動時間
在SysTrace圖中,UI Thread中包含了bindApplication,activityStart,traversal等操作,RenderThread中包含DrawFrame等操作。這些TAG節點是原始碼已經新增的,可參考#3.2中介紹。
I Trace上啟動時間:從bindApplication至第二次traversal完成,可認為UI第一次繪製完成,啟動完成。選中開始點和結束點,可以檢視過程消耗的時間。
4.3 adb shell am start -W
在統計APP啟動時間時,系統為我們提供了adb命令,可以輸出啟動時間
TotalTime: 表示新應用啟動的耗時,包括新程式的啟動和 Activity 的啟動,但不包括前一個應用 Activity pause 的耗時
系統在繪製完成後,ActivityManagerService會回撥該方法,統計時間不如SysTrace準確,但是能夠方便我們通過指令碼多次啟動測量TotalTime,對比版本間啟動時間差異。
4.4 埋點
通過APP啟動生命週期中,關鍵位置加入時間點記錄,達到測量目的。
4.5 錄屏
錄屏方式收集到的時間,更接近於使用者的真實體感。
5 優化
為了讓使用者在進入APP之後,更快更流暢的使用服務,所以會在啟動過程中,提前對一些基礎庫和組建進行初始化操作,這就意味著系統有限的資源會被搶佔,影響啟動時間。啟動時間的優化,是一個平衡效能和體驗的過程。
通過Systrace工具分析,我們發現愛奇藝愛奇藝安卓APP啟動過程中一些問題,接下來,我們就結合具體的業務實踐,進行啟動問題進行優化。
5.1 區分程式初始化Application
由#3我們瞭解到,對於一個app而言,App內元件可以執行在不同的程式之中。舉個例子: 一個APP擁有主程式,外掛程式,下載程式三個程式,會在啟動階段建立相應的元件,但只有一個QYApplication繼承自系統Application,建立三次程式,QYApplication中attach(),onCreate()方法都會被執行三次。
每個程式說需要初始化的內容肯定是不一樣的,所以,為了防止資源的浪費,我們需要區分程式,初始化Appcation.
成果:對多程式應用而言,通過對初始化內容進行梳理,合理區分初始化,會大幅減少記憶體和CPU佔用。
5.2 非同步處理耗時任務
子執行緒處理耗時任務,主執行緒做的事情越少,越早進入Acitivity繪製階段,介面越早展現。
注意:
-
不在主執行緒做耗時任務,如檔案,網路等
-
啟動階段初始化任務,儘量在非同步執行緒處理
-
主執行緒,不用等待或者依賴於子執行緒任務
進一步優化:可以自建執行緒池,維持一定執行緒個數,管理任務佇列。
5.3 防止多執行緒搶佔CPU
Android系統資源有限,特別是CPU資源,理論上來說,UI執行緒執行的任務,也無法保證一直被排程狀態,當併發的執行緒數過多,UI執行緒時間片會更短,從而導致啟動時間被變慢。
下面羅列一些常見,容易造成CPU被搶佔的場景:
成果:通過對執行時間較久,執行頻率的業務進行優化,將CPU佔有率維持在合理的程度,會大幅減少啟動時間,減少300ms以上。
5.4 系統API使用
部分系統的API使用是阻塞性的,檔案很小可能無法感知,當檔案過大,或者使用頻繁時,可能造成阻塞。例如:
-
SharedPreference.Editor提交操作:
-
commit方法屬於屬於阻塞性質API,建議使用apply。
-
此外,我們知道,SP檔案的儲存是一個XML檔案,以key-value形式儲存,當業務過多時,需要拆分為多個檔案儲存,防止檔案過大,出現讀取耗時及ANR。
-
進一步優化,可對啟動階段,頻繁的SP操作在記憶體中,統一提交。
-
AssetManager.open操作: Android開發中,我們有時會將資原始檔放在assets目錄中,然後使用open操作讀取檔案,如果檔案過大,需要在非同步執行緒中執行。
成果:隨著業務量日積月累,正常的系統API的使用,也可能出現問題,通過排除,可減少50-100ms。
5.5 精簡佈局
佈局的複雜程度,直接影響繪製的時間。
舉個例子,在啟動過程中,會有需要大的背景圖,只有第一次安裝時使用,後續屬性設定為android:visibility="gone",但是,雖然設定了gone屬性,不會顯示,但依舊會被解析。
建議:
-
減少佈局層次
-
無用資源使用ViewStub,使用時載入
成果:啟動階段的佈局較簡單,通過優化背景圖片的載入,減少50-100ms。
5.6 Service延後初始化
App啟動中過程中,經常進行Service初始化操作,由於Service使用一般不涉及介面,可能會認為初始化生命週期不在主執行緒中,其實不然,在3.2的啟動過程原始碼介紹中講到,Service的生命週期,也屬於主執行緒Handler接收的Message之一。
建議:Service生命週期中,注意邏輯執行時間效能優化,初始化儘量延後。
成果:取決於初始化Service的生命週期執行時間,可減少200ms以上。
5.7 將任務delay至首頁繪製完成後
對於APP首頁展示不需要的初始化邏輯,可延後至首頁繪製完成後初始化。
注意:
-
需要post兩次才能保證在第一次繪製之後顯示,因為,系統繪製會執行兩次Performtraversal。
進一步優化:可將業務邏輯的初始化劃分為,首頁繪製後,5s,10s,20s三個階段分別初始化,防止首頁繪製執行任務過多造成掉幀。
成果:釋放繪製階段的CPU,可將複雜的繪製提前200ms以上。
6 監控
穩定的使用者體驗依賴於持續的監控,愛奇藝為監控啟動效能建立了一套監控體系,測試,工具,開發等幾個團隊從不同的緯度搭建不同的監控方案
-
1.測試:錄屏,從使用者的真實體驗角度,獲取最準確的啟動時間。
-
2.實時監控:通過埋點,大資料取樣投遞獲取真實線上環境資料,從地域,時間,機型,app版本,系統版本等各個緯度對啟動時間進行監控。
-
3.指令碼測試:通過對指令碼,對同一收集多次啟動資料進行收集,通過不同版本間的對比,監控啟動時間的變化情況。
7 SysTrace擴充套件
SysTrace通過TAG節點可以清晰展現,啟動過程以及方法執行時間,但是,從發現問題,然後通過節點去定位問題,是一件很繁瑣的工作,如果你們工程編譯又比較慢,簡直讓人崩潰。
7.1 自動化TAG注入
在Android工程編譯的過程中,指定class,在方法前後,自動化插入Trace節點,統計方法執行時間。
流程:
-
1.在編譯的過程中,插入自定義Task任務,
-
2.讀取配置檔案,檔案中包含了需要注入java檔名和路徑名和method
-
3.找到需要注入的class檔案,然後通過ASM改變位元組碼,方法前後,插入自定義自定義方法
通過工具的操作,能夠做到不用修改原有工程檔案,自動在打包時注入TAG節點和邏輯程式碼,配置檔案可以迴圈利用,提高分析效率,節能環保。
8 優化結果
啟動時間,由於不同的機型效能同,Android系統版本不同,同一APP版本啟動時間,相差很大,所以統計一般以同一手機,不同版本做比較,儘量保證手機狀態一致。
SysTrace手機優化時間對比:
指令碼多次啟動時間收集對比:
經過多個版本的持續優化,有無廣告兩種不同的場景下,啟動時間分別減少40%和35%,啟動速度得到了較大的提升。
9 總結
啟動時間的優化和監控,是一項長期的任務,需要對異常的情況進行分析,對可能造成阻塞的程式碼邏輯進行合理的優化,非常感謝各個業務團隊支援和配合。
以上就是全部啟動時間優化相關的內容,謝謝大家能夠閱讀到這裡,如果有更好的建議,歡迎交流!
【本文轉載自微信公眾號: 愛奇藝技術產品團隊,ID:iQIYI-TP,轉載授權請聯絡原作者 】
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2158341/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 支付寶客戶端架構解析:Android 客戶端啟動速度優化之「垃圾回收」客戶端架構Android優化
- 支付寶客戶端架構解析:iOS 客戶端啟動效能優化初探客戶端架構iOS優化
- Android App應用啟動分析與優化AndroidAPP優化
- Netty原始碼分析(三):客戶端啟動Netty原始碼客戶端
- Android效能優化之App應用啟動分析與優化Android優化APP
- 有道詞典Android客戶端包體積優化之路Android客戶端優化
- android客戶端與服務端互動的三種方式Android客戶端服務端
- 筆記:MMM客戶端啟動流程筆記客戶端
- php與ethereum客戶端互動PHP客戶端
- Android客戶端網路預連線優化機制探究Android客戶端優化
- vue客戶端渲染首屏優化之道Vue客戶端優化
- Android實現Thrift服務端與客戶端Android服務端客戶端
- 客戶端動態化系列之——URLRoute客戶端
- 自己動手寫個 Android客戶端Android客戶端
- 移動端圖片開啟及返回客戶端客戶端
- 啟動多個zabbix_agented客戶端客戶端
- Android 效能優化 ---- 啟動優化Android優化
- 支付寶客戶端架構分析:自動化日誌收集及分析客戶端架構
- Android客戶端專案元件化實踐Android客戶端元件化
- [Parallax Animation]實現知乎 Android 客戶端啟動頁視差滾動效果Android客戶端
- QQ音樂Android客戶端Web頁面通用效能優化實踐Android客戶端Web優化
- Android篇 | 愛奇藝App啟動最佳化實踐分享AndroidAPP
- android冷啟動優化Android優化
- 基於XMPP實現android客戶端與伺服器的互動Android客戶端伺服器
- 如何開啟客戶端加密特性客戶端加密
- Android效能優化筆記(一)——啟動優化Android優化筆記
- Android應用優化之冷啟動優化Android優化
- 面試Tip:Android優化之APP啟動優化面試Android優化APP
- Web端與Client客戶端資料互動方案選擇Webclient客戶端
- Redis客戶端選型再分析Redis客戶端
- EVE-NG初次啟動及WEB客戶端訪問Web客戶端
- 急!!jsp可以啟動客戶端應用程式嗎?JS客戶端
- Android客戶端效能優化(魅族資深工程師毫無保留奉獻)Android客戶端優化工程師
- 前端效能優化:客戶端從輸入到展示講解前端優化客戶端
- 微信客戶端團隊負責人技術訪談:如何著手客戶端效能監控和優化客戶端優化
- iOS作業系統-- App啟動流程分析與優化iOS作業系統APP優化
- flutter版本的玩Android客戶端FlutterAndroid客戶端
- zabbix客戶端無法啟動並且沒有日誌客戶端