android冷啟動
⑴ Android 性能優化之啟動加速
當點擊app的啟動圖標時,安卓系統會從Zygote進程中fork創建出一個新的進程分配給該應用,之後會依次創建和初始化Application類、創建MainActivity類、載入主題樣式Theme中的
windowBackground等屬性設置給MainActivity以及配置Activity層級上的一些屬性、再inflate布局、當onCreate/onStart/onResume方法都走完了後最後才進行contentView的measure/layout/draw顯示在界面上,所以直到這里,
應用的第一次啟動才算完成,這時候我們看到的界面也就是所說的第一幀。所以,總結一下,應用的啟動流程如下:
Application的構造器方法——>attachBaseContext()——>onCreate()——>Activity的構造方法——>onCreate()——>配置主題中背景等屬性——>onStart()——>onResume()——>測量布局繪制顯示在界面上。
1、冷啟動:當啟動應用時,後台沒有該應用的進程,這時系統會重新創建一個新的進程分配給該應用,這個啟動方式就是冷啟動。
2、熱啟動:當啟動應用時,後台已有該應用的進程(例:按back鍵、在已有進程的情況下,這種啟動會從已有的進程中來啟動應用,這個方式叫熱啟動
1、冷啟動:冷啟動因為系統會重新創建一個新的進程分配給它,所以會先創建和初始化Application類,再創建和初始化MainActivity類(包括一系列的測量、布局、繪制),最後顯示在界面上。
2、熱啟動:熱啟動因為會從已有的進程中來啟動,所以熱啟動就不會走Application這步了,而是直接走MainActivity(包括一系列的測量、布局、繪制),所以熱啟動的過程只需要創建和初始化一個MainActivity就行了,而不必創建和初始化Application
黑白屏產生原因:當我們在啟動一個應用時,系統會去檢查是否已經存在這樣一個進程,如果不存在,系統的服務會先檢查startActivity 中的intent 的信息,然後在去創建進程,最後啟動Acitivy,即冷啟動。
而啟動出現白黑屏的問題,就是在這段時間內產生的。系統在繪制頁面載入布局之前,首先會初始化窗口(Window),而在進行這一步操作時,系統會根據我們設
置的Theme 來指定它的Theme 主題顏色,我們在Style 中的設置就決定了顯示的是白屏還是黑屏。
1.Application 優化(懶載入,延時載入)
2.UI效果,背景圖
3.fragment的懶載入
4.延時載入
⑵ 安卓大屏導航冷啟動和熱啟動的區別
冷啟動:
在啟動應用時,系統中沒有該應用的進程,這時系統會創建一個新的進程分配給該應用;
熱啟動:
在啟動應用時,系統中已有該應用的進程(例:按back鍵、home鍵,應用雖然會退出,但是該應用的進程還是保留在後台);
二、冷啟動、熱啟動的區別
冷啟動:系統沒有該應用的進程,需要創建一個新的進程分配給應用,所以會先創建和初始化Application類,再創建和初始化MainActivity類(包括一系列的測量、布局、繪制),最後顯示在界面上。 熱啟動: 從已有的進程中來啟動,不會創建和初始化Application類,直接創建和初始化MainActivity類(包括一系列的測量、布局、繪制),最後顯示在界面上。
三、冷啟動時間的計算
API19 之後,系統會出列印日誌輸出啟動的時間; 冷啟動時間 = 應用啟動(創建進程) —> 完成視圖的第一次繪制(Activity內容對用戶可見);
四、冷啟動流程
Zygote進程中fork創建出一個新的進程; 創建和初始化Application類、創建MainActivity; inflate布局、當onCreate/onStart/onResume方法都走完; contentView的measure/layout/draw顯示在界面上;
總結:
Application構造方法 –> attachBaseContext() –> onCreate() –> Activity構造方法 –> onCreate() –> 配置主題中背景等屬性 –> onStart() –> onResume() –> 測量布局繪制顯示在界面上。
五、冷啟動的優化
減少在Application和第一個Activity的onCreate()方法的工作量; 不要讓Application參與業務的操作; 不要在Application進行耗時操作; 不要以靜態變數的方式在Application中保存數據; 減少布局的復雜性和深度;
1. 冷啟動的定義
冷啟動:啟動應用前,系統中沒有該應用的任何進程信息Application等,啟動5s+。
1.1 冷啟動時間的計算
這個時間值是從應用啟動(創建進程)開始計算,到完成視圖的第一次繪制(即Activity內容對用戶可見)為止。
2. 熱啟動的定義
熱啟動:啟動應用時,後台已有該應用的進程,內存中有應用相關Activity(home鍵退到桌面),啟動1.5s+。
3. 溫啟動的定義
有一些文章有溫啟動這個啟動類型。
溫啟動:啟動應用時,後台已有該應用的進程,內存中沒有應用相關Activity(back鍵退出應用,未清除進程),啟動2s+。
冷熱啟動過程中,會執行的步驟不一樣。
冷啟動:系統會重新創建一個新的進程分配給它,所以會先創建和初始化Application類,再創建和初始化MainActivity類(包括一系列的測量、布局、繪制),最後顯示在界面上。
熱啟動:一個應用從新進程的創建到進程的銷毀,Application只會初始化一次,所以不必創建和初始化Application,直接走MainActivity(包括一系列的測量、布局、繪制)。
二.冷啟動流程
當點擊app的啟動圖標時,安卓系統會從Zygote進程中fork創建出一個新的進程分配給該應用,之後會依次創建和初始化Application類、創建MainActivity類、載入主題樣式Theme中的windowBackground等屬性設置給MainActivity以及配置Activity層級上的一些屬性、再inflate布局、當onCreate/onStart/onResume方法都走完了後最後才進行contentView的measure/layout/draw顯示在界面上,所以直到這里,應用的第一次啟動才算完成,這時候我們看到的界面也就是所說的第一幀。詳細的參考:App(Activity)啟動流程
總結應用的啟動流程如下:
Application的構造器方 -> attachBaseContext() -> onCreate() -> Activity的構造方法 -> onCreate() -> 配置主題中背景等屬性 -> onStart() -> onResume() -> 測量布局繪制顯示在界面上。
三.如何對冷啟動的時間進行優化
冷啟動時,載入Application過程中,可能會消耗很多時間。如果不採取任何措施就會產生長時間的白屏或黑屏效果,讓用戶以為這個應用很卡。消除啟動時的白屏/黑屏,請參考:Android冷啟動實現APP秒開
1、什麼是Android的冷啟動時間?
冷啟動時間是指用戶從手機桌面點擊APP的那一刻起到啟動頁面的Activity調用onCreate()方法之間的這個時間段。
2、在冷啟動的時間段內發生了什麼?
首先我們要知道當打開一個Activity的時候發生了什麼,在一個Activity打開時,如果該Activity所屬的Application還沒有啟動,那麼系統會為這個Activity創建一個進程(每創建一個進程都會調用一次Application,所以Application的onCreate()方法可能會被調用多次),在進程的創建和初始化中,勢必會消耗一些時間,在這個時間里,WindowManager會先載入APP里的主題樣式里的窗口背景(windowBackground)作為預覽元素,然後才去真正的載入布局,如果這個時間過長,而默認的背景又是黑色或者白色,這樣會給用戶造成一種錯覺,這個APP很卡,很不流暢,自然也影響了用戶體驗。
⑶ Android 中應用程序Activity的冷啟動流程
Activity的啟動主要涉及四個進程
SystemServer進程:主要負責管理整個Framework
App進程:app用戶點擊桌面icon時,通過Launcher進程請求SystemServer進程,再通知Zygote孵化的。
Zygote進程:所有的應用進程都是有Zygote孵化出來的,而Zygote進程由init進程孵化出來,init進程的子進程。
Launcher 進程 :Zygote進程孵化的第一個應用進程。
Activity的啟動主要涉及到七個階段
第一階段: Launcher通知AMS要啟動新的Activity(在Launcher所在的進程執行)
第二階段:AMS先校驗一下Activity的正確性,如果正確的話,會暫存一下Activity的信息。然後,AMS會通知Launcher程序pause Activity(在AMS所在進程執行)
第三階段: pause Launcher的Activity,並通知AMS已經paused(在Launcher所在進程執行)
第四階段:檢查activity所在進程是否存在,如果存在,就直接通知這個進程,在該進程中啟動Activity;不存在的話,會調用Process.start創建一個新進程(執行在AMS進程,內部通過socket和Zygote通信,fork一個新進程)
第五階段: 創建ActivityThread實例,執行一些初始化操作,之後進入Loop循環。(執行在新創建的app進程)
第六階段:處理新的應用進程發出的創建進程完成的通信請求,並通知新應用程序綁定Application。如果Application不存在,會調用LoadedApk.makeApplication創建一個新的Application對象。並且通知進程啟動目標Activity組件(執行在AMS進程)
第七階段: 載入MainActivity類,調用onCreate聲明周期方法(執行在新啟動的app進程)
最後我們來簡單總結一下Activity的啟動流程。
1、startActivity
2、Instrumentation請求AMS啟動Activity(Binder)
3、AMS請求Zygote開啟進程
4、Zygote創建應用進程
5、應用進程啟動ActivityThread(主線程)
6、ActivityThread綁定Application
8、ActivityThread啟動Activity
9、調用Activity的onCreate方法
⑷ Android啟動優化概述
Android啟動應用, 按 官方說法 分為冷啟動, 溫啟動和熱啟動.
具體的定義可以看官方文檔, 簡單地說
一般我們只需要關注冷啟動即可.
要想啟動快, 硬體性能必然有影響, 在硬體一定的前提下, 我們要盡量 降低啟動應用時CPU的負載 , 讓CPU有更多的算力投入到啟動流程中:
在做好一些基本原則後, 接著看具體的流程優化點
在應用進程創建後, 首先必然是載入類, 此時一些靜態變數就會初始化了, 因此我們應該
類載入完畢後就是創建 Application 實例了, 因此我們應該
之後會先創建 ContentProvider 和執行 ContentProvider.onCreate() , 因此我們應該
跟接著就會執行 Application.onCreate() 等方法, 因此我們應該
接著就進入 Activity 環節.
同樣第一步會是創建實例, 因此我們應該
在 Activity 進程生命周期後, 第一步就是渲染(inflate)布局, 我們應該
在應用啟動的瞬間, 系統服務會先展示一個空白窗口, 等待應用第一幀繪制完畢後, 再從該窗口切換到應用, 如果啟動耗時較長, 就會明顯看到白屏, 對於這一點, 常見的操作有
可以使用IdleHandler, 在主線程空閑時再執行某些不重要的操作
實際上非同步初始化只是不阻塞主線程, 但是子線程一樣會佔用CPU資源, 讓主線程的執行時間變少, 所以不應該盲目地將所有工作放到子線程.
優化做到最後, 就是在系統流程上做文章了
原理是將啟動時載入的類放到主dex,提升了這些類的內聚,讓更多的類滿足pre-verify的條件,在安裝時就做了校驗和優化,以減少首次載入的耗時,從而優化冷啟動耗時。
Redex 初探與 Interdex:Andorid 冷啟動優化
應用啟動過程中會從apk壓縮包中讀取文件, 該優化的原理是利用Linux中的Pagecache機制, 讓啟動過程會用到的文件盡可能進入緩存中, 減少磁碟IO次數
支付寶 App 構建優化解析:通過安裝包重排布優化 Android 端啟動性能
在Dalvik VM(Android5.0以前)載入類的時候會有一個類校驗過程, 它需要校驗方法的每一個指令, 是一個比較耗時的過程, 可以通過Hook去掉類載入過程中的類驗證過程. 不過對於ART(Android5.0之後)來說, 這個過程在安裝時已經做了, 所以用處不大.
不進入冷啟動, 就不用優化了~
這個Android Studio自帶的工具, 可以看到啟動過程中詳細的方法執行流程, 但是採集數據本身會影響方法執行, 所以不能准確判斷每個方法的耗時, 但是仍可以判斷哪個方法相對來說耗時.
這個工具的好處是可以自定義事件, 可以指定需要採集的數據集, 可以看到線程間的狀態等.
啟動優化的一個關鍵點在於定義啟動結束的點, 以及如何測量啟動時間.
在Android4.4以上, 系統進程會提供一個類似 ActivityManager: Displayed ***: +3s534ms 的日誌, 表示從啟動進程到首次繪制完畢所用的時間.
應用可以在任何時候調用該方法, 觸發系統列印類似 system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms 的日誌
應用可以通過 ViewTreeObserver 來監聽繪制前回調來判斷第一幀的繪制時機, 或者直接在控制項樹的末尾加一個簡單的View, 它 onDraw 調用時即表示頁面(差不多)繪制完畢.
應用啟動過程可以參考 Android Vitals Series' Articles 系列文章
⑸ Android 11 提高 App 冷啟動速度 5% 以上
近一年多以來一直在做性能優化( OOM、Native、ANR 等等),在後面我也會寫一些性能相關的文章,將自己學習和實踐所得分享出來。以今天這篇文章作為開端。
在 Android 11 上增加了一個新的功能 IORap,IORap 將會減少 App 冷啟動耗時,經過在各種設備上測試,App 的啟動速度(冷啟動)平均提高了 5% 以上,部分設備提高了 20% 以上,開發者不需要做任何任何事情,即可享受帶來的啟動優化收益。
IORap 會提前預測需要那些 I/O 並將他們提前,通過這種方式減少 App 啟動耗時。大量的 App 啟動時間很長,是因為 blocking I/O 導致 IO 請求隊列未到達飽和,在預取數據之後同時壓縮 I/O ,App 可以很快的從 kernel pagecache 中訪問預取數據,從而減少 App 啟動耗時。
我們測試了在 Google Play Store 上一些熱門的應用,80% 的 App 在啟動期間,因為 blocking I/O 耗費了 10% 以上的時間,80% 的 App 耗費了 20% 以上的時間。我們在 Google Play Store 上測試了大部分應用都可以從 IORap 中獲得收益。
IORap 作為一個獨立的 service,它通過 IPC 與 package manager,activity manager, perfetto service 等等交互,以下是 IORap 的架構圖。
IORap 基於一定的策略分析預取 I/O ,通過 perfetto 進行跟蹤記錄,會在 kernel pagecache 中添加和刪除的頁面。經過測試,啟動期間通過 perfetto 進行跟蹤記錄造成的開銷可以忽略不計。
基於上面的 perfetto trace,IORap 會在設備空閑時,生成預取列表,預取列表包含啟動期間需要讀取的文件信息(名稱,偏移,長度), IORap 會根據 perfetto trace 分析 mm_pagemap 事件,並將結果 (inode、偏移量、長度) 轉換為 (名稱、偏移量、長度),然後將數據存儲在預取列表中,預取列表是一個 protobuf 文件。
經過上一步,生成預取列表之後,後續運行 App 時 IORap 可以為 App 預取對應的數據,在上一步執行完之後,不在需要 perfetto trace, 開發者不需要做任何事情,系統會在用戶點擊圖標時或者通過 Intent 請求它,執行預取操作,享受帶來的啟動優化。
預取列表不會永久存在,會因為一些事件導致預取列表過時,而被刪除,當 App 更新時,由於更新過程中可能會發生變化,和之前的預取數據會有一些差異,所以不建議在這個階段預取數據,另外 dexopt 會在 App 安裝後進行優化,優化後的 App,數據不會發生改變,這會使預取列表過時,過時的預取列表將被刪除,這時會開始新一輪的 perfetto trace。
通過對比幾個實驗的結果,我們可以確定 IORap 對於低端機和高端機都會有收益,平均而言, IORAP 可以提高 26% 的啟動速度,對於啟動期間有大量 I/O 的 App 會有很大的幫助,例如,Spotify 低端設備和高端設備有兩位數字的優化效果。
在實驗過程中,發現了一個現象 IORap 性能會受到預取數據的影響,跟蹤持續時間對於 IORap 來說非常重要,跟蹤持續時間越短,預取的數據就越少,獲得的性能也越低。另一方面,長時間的預取會導致需要預取的數據過多,這可能會導致啟動速度變慢,我們可以根據 ReportFullyDrawn 事件的時間戳來估計跟蹤持續時間。在正確的調用 reportFullyDrawn 回調可以提高 IORap 的性能。
我們對 IORap 所表現出來的性能非常的興奮,在未來將會朝著以下兩方向進行優化。
可以在 App 啟動完成之後,調用 reportFullyDrawn 來幫助 IORap 進行更好的優化,IORap 主要有助於減少 I/O 阻塞時間,因此可以考慮對 App 啟動進行分析,發現和解決其他可能存在的性能問題。