Dalvik虛擬機(jī)
dex文件
Java虛擬機(jī)運(yùn)行的是java字節(jié)碼,即class文件,而Dalvik虛擬機(jī)執(zhí)行的是專(zhuān)有的dex格式字節(jié)碼,dex文件是由一個(gè)或多個(gè)class文件打包而成。dex體積更小,class文件都有一個(gè)常量池,而dex文件只有一個(gè)常量池,多個(gè)class文件如果有重復(fù)的字符串,在dex文件里只有一份。
dex文件生成:
- javac 把.java文件編譯成.class文件
- dx工具:在sdk/build-tools/中的dx工具,執(zhí)行命令dx --dex --output="文件名.dex" [class文件地址]
- 在jdk 1.8 可能會(huì)出現(xiàn)錯(cuò)誤,提示不支持當(dāng)前版本,所以編譯時(shí)要強(qiáng)制用低版本的jdk編譯,如javac -source 1.7 -target 1.7 [java文件]
odex文件
- odex是Optimized dex 的簡(jiǎn)寫(xiě),即優(yōu)化后的dex文件,主要是為了提高Dalvik虛擬機(jī)的運(yùn)行速度。
- odex文件時(shí)dex文件具體在某個(gè)系統(tǒng)上的優(yōu)化。odex文件優(yōu)化依賴(lài)系統(tǒng)上的幾個(gè)核心模塊,一般是/system/framwork/下的jar包,尤其是core.jar。odex的優(yōu)化及時(shí)把本來(lái)需要在執(zhí)行過(guò)程中做的類(lèi)校驗(yàn)、調(diào)用其他類(lèi)函數(shù)時(shí)的解析等工作提前處理。
Dalvik虛擬機(jī)的啟動(dòng)
在Android系統(tǒng)中,應(yīng)用程序進(jìn)程都是由Zygote進(jìn)程孵化出來(lái)的,而Zygote進(jìn)程是由Init進(jìn)程啟動(dòng)的。Zygote進(jìn)程在啟動(dòng)時(shí)會(huì)創(chuàng)建一個(gè)Dalvik虛擬機(jī)實(shí)例,每當(dāng)它孵化一個(gè)新的應(yīng)用程序進(jìn)程時(shí),都會(huì)將這個(gè)Dalvik虛擬機(jī)實(shí)例復(fù)制到新的應(yīng)用程序進(jìn)程里面去,從而使得每一個(gè)應(yīng)用程序進(jìn)程都有一個(gè)獨(dú)立的Dalvik虛擬機(jī)實(shí)例。Zygote是虛擬機(jī)實(shí)例的孵化器。AndroidRuntime.cpp中ZygoteInit.main()的執(zhí)行會(huì)完成一個(gè)分裂,分裂出來(lái)的子進(jìn)程繼續(xù)初始化Java層的架構(gòu),這個(gè)分裂出來(lái)的進(jìn)程就是system_server。每當(dāng)系統(tǒng)要求執(zhí)行一個(gè)Android應(yīng)用程序,Zygote就會(huì)fork出一個(gè)子進(jìn)程來(lái)執(zhí)行該應(yīng)用程序。system_server是應(yīng)用與Zygote之間交流的橋梁,通過(guò)socket進(jìn)行通信。Android系統(tǒng)啟動(dòng)加載完內(nèi)核后,第一個(gè)執(zhí)行的是init進(jìn)程,init進(jìn)程首先要做的是設(shè)備的初始化工作,然后讀取inic.rc文件并啟動(dòng)系統(tǒng)中的重要外部程序 Zygote。Zygote進(jìn)程是Android所有進(jìn)程的孵化器進(jìn)程,它啟動(dòng)后會(huì)首先初始化Dalvik虛擬機(jī),然后啟動(dòng)system_server并進(jìn)入Zygote模式,通過(guò)socket等候命令。當(dāng)執(zhí)行一個(gè)Android應(yīng)用程序時(shí),system_server進(jìn)程通過(guò)Binder IPC方式發(fā)送命令給Zygote,Zygote收到命令后通過(guò)fork自身創(chuàng)建一個(gè)Dalvik虛擬機(jī)的實(shí)例來(lái)執(zhí)行應(yīng)用程序的入口函數(shù),這樣一個(gè)程序就啟動(dòng)完成了。
Dalvik和Jvm之間的區(qū)別
- Dalvik和Jvm最大的區(qū)別是Dalvik基于寄存器結(jié)構(gòu),而Jvm基于棧結(jié)構(gòu)。一般來(lái)說(shuō)基于寄存器結(jié)構(gòu)的運(yùn)行速度更快,但代碼長(zhǎng)度會(huì)邊長(zhǎng),這也是現(xiàn)在很多cpu采用的結(jié)構(gòu)。
- Dalvik虛擬機(jī)運(yùn)行dex格式的字節(jié)碼,而Jvm虛擬機(jī)運(yùn)行class格式的字節(jié)碼。 Dalvik虛擬機(jī)所占空間小,且可執(zhí)行文件體積小。
- 每Dalvik負(fù)責(zé)進(jìn)程隔離和線程管理,每一個(gè)Android應(yīng)用在底層都會(huì)對(duì)應(yīng)一個(gè)獨(dú)立的Dalvik虛擬機(jī)實(shí)例,其代碼在虛擬機(jī)的解釋下得以執(zhí)行。
Dalvik和ART的區(qū)別
Android Runtime,在android 5.0以后及后續(xù)版本取代Dalvik。
JIT最早在Android 2.2系統(tǒng)中引進(jìn)到Dalvik虛擬機(jī)中,在應(yīng)用程序啟動(dòng)時(shí),JIT通過(guò)進(jìn)行連續(xù)的性能分析來(lái)優(yōu)化程序代碼的執(zhí)行,在程序運(yùn)行的過(guò)程中,Dalvik虛擬機(jī)在不斷的進(jìn)行將字節(jié)碼編譯成機(jī)器碼的工作。 與Dalvik虛擬機(jī)不同的是,ART引入了AOT這種預(yù)編譯技術(shù),在應(yīng)用程序安裝的過(guò)程中,ART就已經(jīng)將所有的字節(jié)碼重新編譯成了機(jī)器碼。應(yīng)用程序運(yùn)行過(guò)程中無(wú)需進(jìn)行實(shí)時(shí)的編譯工作,只需要進(jìn)行直接調(diào)用。因此,ART極大的提高了應(yīng)用程序的運(yùn)行效率,同時(shí)也減少了手機(jī)的電量消耗,提高了移動(dòng)設(shè)備的續(xù)航能力,在垃圾回收等機(jī)制上也有了較大的提升。 為了保證向下兼容,ART使用了相同的Dalvik字節(jié)碼文件(dex),即在應(yīng)用程序目錄下保留了dex文件供舊程序調(diào)用然而.odex文件則替換成了可執(zhí)行與可鏈接格式(ELF)可執(zhí)行文件。一旦一個(gè)程序被ART的dex2oat命令編譯,那么這個(gè)程序?qū)?huì)指通過(guò)ELF可執(zhí)行文件來(lái)運(yùn)行。因此,相對(duì)于Dalvik虛擬機(jī)模式,ART模式下Android應(yīng)用程序的安裝需要消耗更多的時(shí)間,同時(shí)也會(huì)占用更大的儲(chǔ)存空間(指內(nèi)部?jī)?chǔ)存,用于儲(chǔ)存編譯后的代碼),但節(jié)省了很多Dalvik虛擬機(jī)用于實(shí)時(shí)編譯的時(shí)間。
核心庫(kù):Dalvik核心庫(kù)libdvm.so,Art核心庫(kù)libart.so
Art的核心是OAT文件。OAT文件是一種Android私有ELF文件格式,它不僅包含有從DEX文件翻譯而來(lái)的本地機(jī)器指令,還包含有原來(lái)的DEX文件內(nèi)容。