為什麼應用程式在Android 7.0之後安裝和執行都變得更快?
需要了解幾個概念
-
Dalvik 虛擬機器
負責解釋dex檔案為機器碼,每次執行程式碼,都需要Dalvik將dex程式碼翻譯為微處理器指令,然後交給系統處理,這樣效率不高。
-
JIT(Just-In-Time)
為了解決上面的問題,Google在2.2版本添加了JIT編譯器,當App執行時,每當遇到一個新類,JIT編譯器就會對這個類進行編譯,經過編譯後的程式碼,會被優化成相當精簡的原生型指令碼(即native code),這樣在下次執行到相同邏輯的時候,速度就會更快。
當然使用JIT也不一定加快執行速度,如果大部分程式碼的執行次數很少,那麼編譯花費的時間不一定少於執行dex的時間。所以JIT不對所有dex程式碼進行編譯,而是隻編譯執行次數較多的dex為本地機器碼。
有一點需要注意,dex位元組碼翻譯成本地機器碼是發生在應用程式的執行過程中的,並且應用程式每一次重新執行的時候,都要做重做這個翻譯工作,所以這個工作並不是一勞永逸,每次重新開啟App,都需要進行JIT編譯。
對執行次數頻繁的dex程式碼進行編譯和優化,減少以後使用時的翻譯時間,雖然可以加快Dalvik執行速度,但是還是有弊病,那就是將dex翻譯為本地機器碼也要佔用時間
-
ART 虛擬機器
與Dalvik不同,在ART 環境中,應用在第一次安裝的時候,位元組碼就會預先編譯成機器碼,使其成為真正的本地應用。之後開啟App的時候,直接使用本地機器碼執行,因此執行速度提高。
ART需要應用程式在安裝時,就把程式程式碼轉換成機器語言,所以這會消耗掉更多的儲存空間,但消耗掉空間的增幅通常不會超過應用程式碼包大小的20%。由於有了一個轉碼的過程,所以應用安裝時間難免會延長
-
AOT
對比JIT就很好理解了,一個是執行時編譯,一個是安裝時編譯。
使用JIT編譯器時,App優缺點
-
優點
-
安裝迅速
-
安裝時所需容量小
-
缺點
-
使用了JIT,在執行時編譯,導致電量消耗快
-
JIT本身也有開銷
使用AOT編譯器的時候,App優缺點
-
優點
-
啟動快
-
執行快(不卡頓),因為直接執行的機器碼
-
電量消耗少,沒有了JIT
-
缺點
-
安裝慢,因為安裝的時候需要將 .dex 編譯成本地機器碼。
-
需要更大的安裝空間,因為將 .dex 編譯成機器碼之後,需要儲存起來。
AOT編譯方案面臨的挑戰
由於系統更新時,所有的應用都需要重新安裝,這會導致所有的應用都需要在重新編譯一遍,如果你的應用賊多的話……。
編譯之後的native code會比較大,消耗了儲存空間,如果你的應用非常大的話,一些小容量的手機可能無法安裝。
這中編譯行為對動態apk的支援不是很好。
可以看到,JIT與AOT的優缺點完全是反過來的,Google大佬就將這兩個方案結合起來,整出了混合編譯。
Google大佬的解決方案,混合編譯發現JIT又回來了。
當用戶安裝App的時候,不再進行預編譯了,這個和KitKat的時候一樣。當用戶安裝之後立即使用該App,仍然使用JIT編譯模式來執行App,但是同時會生成一個離線的 profile 檔案,這個 profile 檔案會記錄JIT執行時的所有 hot code(熱點程式碼)資訊。然後在未來的某個時間點,Android Framework 會基於這個 profile 檔案來啟動一個預編譯行為,它只便於記錄的熱點程式碼。
在 JIT 階段,它帶來的好處:
-
快速安裝
-
系統快速更新
在 AOT 階段,它帶來的好處:
-
快速啟動,更好的執行效能
-
低消耗:CPU,儲存空間,電量…
ART混合編譯模式
-
一些使用者只使用App中的一部分功能,只有這些被頻繁使用的部分(這個功能涉及到的程式碼)才值得被編譯成 native code。
-
在 JIT 階段,我們可以很容易的找到經常被使用的程式碼。
-
使用 AOT 來加快這些經常使用的用例。
-
避免在一些基本不適用的程式碼上花費開銷。
混合編譯與AOT的效能比較
有意思的是,AOT與JIT在Micro Benchmark測試中各有優劣。
參考文件如下所示:
https://www.youtube.com/watch?v=TCJLFqhC1VE
https://www.cnblogs.com/keyarchen/p/6063096.html