眾所周知怜跑,android系統(tǒng)的底層操作系統(tǒng)是Linux顽冶,上層應(yīng)用程序是用java代碼或者kotlin來編寫的彪置,那么這些用高級(jí)語言編寫的應(yīng)用程序是如何運(yùn)行在linux系統(tǒng)之上呢挂洛?想必大家都知道了吹埠,鏈接這兩者的橋梁就是虛擬機(jī)斩郎。那么android的虛擬機(jī)和傳統(tǒng)的JVM有什么區(qū)別脑融,又有什么關(guān)系呢?要回答這些問題缩宜,我們先看下兩者在編譯成虛擬機(jī)可以執(zhí)行的字節(jié)碼或者機(jī)器語言過程的對(duì)比:
傳統(tǒng)的JVM肘迎,以Sun公司的HotSpot為例:
Android ART:
兩者的過程看,都會(huì)經(jīng)過javac編譯成class 文件锻煌,但是之后就走向了不同的方向
HotSpot生成class文件后就通過類加載器加載字節(jié)碼文件到虛擬機(jī)妓布,虛擬機(jī)經(jīng)過解釋器或者JIT 生成機(jī)器碼交由底層操作系統(tǒng)去執(zhí)行,而android在4.4版本后宋梧,Java文件在編譯成class文件,然后經(jīng)過Android平臺(tái)的dx工具轉(zhuǎn)換為Dex文件后,同Native code(JNI)和資源一起打包成apk,apk安裝到手機(jī)后解壓出Dex文件匣沼。Dalvik會(huì)通過dexopt工具將Dex優(yōu)化,成為Odex文件,Odex文件的效率比Dex高,但其中大部分代碼仍然需要每次執(zhí)行時(shí)編譯;而ART則會(huì)將Dex通過dex2oat工具編譯得到一個(gè)ELF文件,它是一個(gè)可執(zhí)行的文件。?在ART中捂龄,打包在APK里面的Dex字節(jié)碼是通過LLVM翻譯成本地機(jī)器指令的释涛。所以說經(jīng)過優(yōu)化編譯后,進(jìn)入到ART執(zhí)行的就已經(jīng)是機(jī)器碼了倦沧,效率大大的提高了唇撬。
進(jìn)入到虛擬機(jī)內(nèi)部后,具體的執(zhí)行方式又有什么不同呢展融?這就要回歸到基于棧虛擬機(jī)和基于寄存器虛擬機(jī)兩者的對(duì)比來看了窖认。
HotSpot基于棧的,基于棧的虛擬機(jī)有一個(gè)操作數(shù)棧的概念告希,虛擬機(jī)在進(jìn)行真正的運(yùn)算時(shí)都是直接與操作數(shù)棧(operand stack)進(jìn)行交互扑浸,不能直接操作內(nèi)存中數(shù)據(jù),也就是說不管進(jìn)行何種操作都要通過操作數(shù)棧來進(jìn)行燕偶,即使是數(shù)據(jù)傳遞這種簡單的操作喝噪。這樣做的直接好處就是虛擬機(jī)可以無視具體的物理架構(gòu),特別是寄存器杭跪。但缺點(diǎn)也顯而易見仙逻,就是速度慢,因?yàn)闊o論什么操作都要通過操作數(shù)棧這一結(jié)構(gòu)涧尿。
例如執(zhí)行”a = b + c”系奉,在基于棧的虛擬機(jī)上字節(jié)碼指令如下所示:
I1: LOAD C
I2: LOAD B
I3: ADD
I4: STORE A
操作數(shù)棧上的變化如下圖所示:
物理上操作如下:
基于寄存器的
比如a= b+c
指令只有一條:
I1: add a, b, c
物理機(jī)器上執(zhí)行:
綜上對(duì)比:
(1)指令條數(shù):棧式虛擬機(jī)多?
(2)代碼尺寸:棧式虛擬機(jī)?
(3)移植性:棧式虛擬機(jī)移植性更好?
(4)指令優(yōu)化:寄存器式虛擬機(jī)更能優(yōu)化
我們?cè)賮砜唇?jīng)過編譯后生成的class文件和dex文件,class文件java文件經(jīng)過javac編譯器生成的姑廉,有多少java文件就有多少個(gè)class文件缺亮,對(duì)于手機(jī)這樣對(duì)內(nèi)存和存儲(chǔ)空間有限的設(shè)備來說,太多的class的文件就有點(diǎn)不劃算了,而且查找太耗時(shí)萌踱,必須優(yōu)化葵礼。而Dex記錄整個(gè)工程中所有類文件的信息,注意是“整個(gè)工程”并鸵,即所有類文件信息鸳粉,并去除冗余,區(qū)域復(fù)用并整合园担。下面給出兩者文件的對(duì)比圖:
以上只是大概列出了ART區(qū)別于傳統(tǒng)的JVM比較重大的區(qū)別届谈,具體內(nèi)部實(shí)現(xiàn)上也有很大的區(qū)別。比如AOT弯汰,允許有多個(gè)ART實(shí)例艰山,內(nèi)存管理方式等等。最后ART是如何被創(chuàng)建出來呢咏闪?
Android系統(tǒng)在啟動(dòng)的時(shí)候曙搬,會(huì)創(chuàng)建一個(gè)Zygote進(jìn)程,充當(dāng)應(yīng)用程序進(jìn)程孵化器鸽嫂。Zygote進(jìn)程在啟動(dòng)的過程中纵装,又會(huì)創(chuàng)建一個(gè)ART虛擬機(jī)。Zygote進(jìn)程是通過復(fù)制自己來創(chuàng)建新的應(yīng)用程序進(jìn)程的据某。這意味著Zygote進(jìn)程會(huì)將自己的ART虛擬機(jī)復(fù)制給應(yīng)用程序進(jìn)程搂擦。通過這種方式就可以大大地提高應(yīng)用程序的啟動(dòng)速度,因?yàn)檫@種方式避免了每一個(gè)應(yīng)用程序進(jìn)程在啟動(dòng)的時(shí)候都要去創(chuàng)建一個(gè)ART哗脖。事實(shí)上,Zygote進(jìn)程通過自我復(fù)制的方式來創(chuàng)建應(yīng)用程序進(jìn)程扳还,省去的不僅僅是應(yīng)用程序進(jìn)程創(chuàng)建ART虛擬機(jī)的時(shí)間才避,還能省去應(yīng)用程序進(jìn)程加載各種系統(tǒng)庫和系統(tǒng)資源的時(shí)間,因?yàn)樗鼈冊(cè)赯ygote進(jìn)程中已經(jīng)加載過了氨距,并且也會(huì)連同ART虛擬機(jī)一起復(fù)制到應(yīng)用程序進(jìn)程中去桑逝。
最后我們總結(jié)下本文的主要內(nèi)容:
1,傳統(tǒng)虛擬機(jī)和ART編譯過程的不一致
2俏让,基于棧和基于寄存器的區(qū)別
3楞遏,傳統(tǒng)虛擬機(jī)和ART執(zhí)行文件的不一致
4,ART的創(chuàng)建過程
ART雖然是一個(gè)虛擬機(jī)首昔,但是它已經(jīng)不遵守虛擬機(jī)規(guī)范寡喝,但是一些JVM的核心理念還是保留了,比如垃圾回收機(jī)制等勒奇,如果想要更好的理解ART预鬓,建議還是先閱讀JVM規(guī)范,循序漸進(jìn)赊颠,慢慢摸索格二。