自 2008 年 9 月 23 日對(duì)外發(fā)布第一個(gè)版本 Android 1.0 以來(lái),在摩爾定律和安迪比爾定律的共同作用下,Android 系統(tǒng)以每年至少一次重大更新(2016 年至今每年一次)速度進(jìn)行迭代,在進(jìn)行版本迭代的過(guò)程中,Android 虛擬機(jī)的發(fā)展不可忽視。
Android 誕生之初
在 Android 系統(tǒng)初期,不同于 Java 平臺(tái)使用 JVM 加載字節(jié)碼文件(.class),Android 系統(tǒng)由 Dalvik 擔(dān)任虛擬機(jī)的角色,每次運(yùn)行程序的時(shí)候,Dalvik 負(fù)責(zé)加載 dex/odex 文件并解析成機(jī)器碼交由系統(tǒng)調(diào)用。
Android 2.2 —— JIT 首次登場(chǎng)
為了適應(yīng)硬件速度的提升,Android 系統(tǒng)系統(tǒng)也在不斷更新,單一的 Dalvik 虛擬機(jī)已經(jīng)漸漸地滿足系統(tǒng)的要求了,2010 年 5 月 20 日,Google 發(fā)布 Android 2.2(Froyo凍酸奶),在這個(gè)版本中,Google 在 Android 虛擬中加入了 JIT 編譯器(Just-In-Time Compiler)。
和其他大多數(shù) JVM 一樣,Dalvik 使用 JIT 進(jìn)行即時(shí)編譯,借助 Java HotSpot VM,JIT 編譯器可以對(duì)執(zhí)行次數(shù)頻繁的 dex/odex 代碼進(jìn)行編譯與優(yōu)化,將 dex/odex 中的 Dalvik Code(Smali 指令集)翻譯成相當(dāng)精簡(jiǎn)的 Native Code 去執(zhí)行,JIT 的引入使得 Dalvik 的性能提升了 3~6 倍。
但是 JIT 模式的缺點(diǎn)也不容忽視:
- 每次啟動(dòng)應(yīng)用都需要重新編譯
- 運(yùn)行時(shí)比較耗電,造成電池額外的開(kāi)銷
Andorid 4.4 —— ART 和 AOT
2013 年 10 月 31 日,Google 發(fā)布 Android 4.4(奇巧Kitkat),帶來(lái)了全新的虛擬機(jī)運(yùn)行環(huán)境 ART(Android RunTime)的預(yù)覽版和全新的編譯策略 AOT(Ahead-of-time),需要注意的是,彼時(shí) ART 是和 Dalvik 共存的,用戶可以在兩者之間進(jìn)行選擇(感覺(jué)怪怪的,用戶可是小透明啊)。
Android 5.0 —— ART 全面取代 Dalvik
2014 年 10 月 16 日,Google發(fā)布Android 5.0(棒棒糖Lollipop),ART 全面取代 Dalvik 成為 Android 虛擬機(jī)運(yùn)行環(huán)境,至此,Dalvik 退出歷史舞臺(tái),AOT 也成為唯一的編譯模式。
AOT 和 JIT 的不同之處在于:JIT 是在運(yùn)行時(shí)進(jìn)行編譯,是動(dòng)態(tài)編譯,并且每次運(yùn)行程序的時(shí)候都需要對(duì) odex 重新進(jìn)行編譯;而 AOT 是靜態(tài)編譯,應(yīng)用在安裝的時(shí)候會(huì)啟動(dòng) dex2oat 過(guò)程把 dex 預(yù)編譯成 ELF 文件,每次運(yùn)行程序的時(shí)候不用重新編譯,是真正意義上的本地應(yīng)用。
另外,相比于 Dalvik,ART 對(duì) Garbage Collection(GC)過(guò)程的也進(jìn)行了改進(jìn):
- 只有一次 GC 暫停(Dalvik 需要兩次)
- 在 GC 保持暫停狀態(tài)期間并行處理
- 在清理最近分配的短時(shí)對(duì)象這種特殊情況中,回收器的總 GC 時(shí)間更短
- 優(yōu)化了垃圾回收的工效,能夠更加及時(shí)地進(jìn)行并行垃圾回收,這使得 GC_FOR_ALLOC 事件在典型用例中極為罕見(jiàn)
- 壓縮 GC 以減少后臺(tái)內(nèi)存使用和碎片
AOT 模式解決了應(yīng)用啟動(dòng)和運(yùn)行速度和耗電問(wèn)題的同時(shí)也帶來(lái)了另外兩個(gè)問(wèn)題:
- 應(yīng)用安裝和系統(tǒng)升級(jí)之后的應(yīng)用優(yōu)化比較耗時(shí)
- 優(yōu)化后的文件會(huì)占用額外的存儲(chǔ)空間
這也給 Android 系統(tǒng)后續(xù)的優(yōu)化埋下了伏筆。
Android 7.0 —— JIT 回歸
用過(guò) Android 手機(jī)的人應(yīng)該都知道,在 Android 5.x 和 6.x 的機(jī)器上,系統(tǒng)每次 OTA 升級(jí)完成重啟的時(shí)候都會(huì)有個(gè)應(yīng)用優(yōu)化的過(guò)程,這個(gè)過(guò)程就是剛才所說(shuō)的 dex2oat 過(guò)程,這個(gè)過(guò)程比較耗時(shí)并且會(huì)占用額外的存儲(chǔ)空間。
2016年8月22日,Google發(fā)布Android 7.0(牛軋?zhí)荖ougat),JIT 編譯器回歸,形成 AOT/JIT 混合編譯模式,這種混合編譯模式的特點(diǎn)是:
- 應(yīng)用在安裝的時(shí)候 dex 不會(huì)被編譯
- 應(yīng)用在運(yùn)行時(shí) dex 文件先通過(guò)解析器(Interpreter)后會(huì)被直接執(zhí)行(這一步驟跟 Android 2.2 - Android 4.4之前的行為一致),與此同時(shí),熱點(diǎn)函數(shù)(Hot Code)會(huì)被識(shí)別并被 JIT 編譯后存儲(chǔ)在 jit code cache 中并生成 profile 文件以記錄熱點(diǎn)函數(shù)的信息。
- 手機(jī)進(jìn)入 IDLE(空閑) 或者 Charging(充電) 狀態(tài)的時(shí)候,系統(tǒng)會(huì)掃描 App 目錄下的 profile 文件并執(zhí)行 AOT 過(guò)程進(jìn)行編譯。
可以看出,混合編譯模式綜合了 AOT 和 JIT 的各種優(yōu)點(diǎn),使得應(yīng)用在安裝速度加快的同時(shí),運(yùn)行速度、存儲(chǔ)空間和耗電量等指標(biāo)都得到了優(yōu)化。
總結(jié)
Android 系統(tǒng)從誕生到現(xiàn)在,經(jīng)歷了幾次重要更新,最終選擇了折衷的方案,使得系統(tǒng)的安裝和運(yùn)行的時(shí)候各項(xiàng)指標(biāo)都得到了優(yōu)化,至此,Android 虛擬機(jī)的發(fā)展進(jìn)程告一段落。但是,隨著硬件性能的不斷提升,相信谷歌的腳步不會(huì)就此停止,期待谷歌能在未來(lái)給我們不斷帶來(lái)驚喜。
參考文章/視頻
https://www.youtube.com/watch?v=TCJLFqhC1VE
https://source.android.com/devices/tech/dalvik/jit-compiler
http://www.lxweimin.com/p/9a3a4eb32a04
https://zh.wikipedia.org/wiki/Android%E7%89%88%E6%9C%AC%E5%88%97%E8%A1%A8#cite_note-42
如果你對(duì)文章內(nèi)容有不同意見(jiàn),歡迎留言,我們一同探討。