從JVM到ART

眾所周知,android系統(tǒng)的底層操作系統(tǒng)是Linux,上層應(yīng)用程序是用java代碼或者kotlin來編寫的,那么這些用高級語言編寫的應(yīng)用程序是如何運(yùn)行在linux系統(tǒng)之上呢?想必大家都知道了,鏈接這兩者的橋梁就是虛擬機(jī)。那么android的虛擬機(jī)和傳統(tǒng)的JVM有什么區(qū)別,又有什么關(guān)系呢?要回答這些問題,我們先看下兩者在編譯成虛擬機(jī)可以執(zhí)行的字節(jié)碼或者機(jī)器語言過程的對比:

傳統(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ī)兩者的對比來看了。

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í)行:


綜上對比:

(1)指令條數(shù):棧式虛擬機(jī)多?

(2)代碼尺寸:棧式虛擬機(jī)?

(3)移植性:棧式虛擬機(jī)移植性更好?

(4)指令優(yōu)化:寄存器式虛擬機(jī)更能優(yōu)化

我們再來看經(jīng)過編譯后生成的class文件和dex文件,class文件java文件經(jīng)過javac編譯器生成的,有多少java文件就有多少個(gè)class文件,對于手機(jī)這樣對內(nèi)存和存儲(chǔ)空間有限的設(shè)備來說,太多的class的文件就有點(diǎn)不劃算了,而且查找太耗時(shí),必須優(yōu)化。而Dex記錄整個(gè)工程中所有類文件的信息,注意是“整個(gè)工程”,即所有類文件信息,并去除冗余,區(qū)域復(fù)用并整合。下面給出兩者文件的對比圖:

以上只是大概列出了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)樗鼈冊赯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),慢慢摸索。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容