Dalvik虛擬機(jī)
DVM是Dalvik Virtual Machine的縮寫(xiě),是Android4.4及以前使用的虛擬機(jī)顽分,所有android程序都運(yùn)行在android系統(tǒng)進(jìn)程里赌莺,每個(gè)進(jìn)程對(duì)應(yīng)著一個(gè)Dalvik虛擬機(jī)實(shí)例南蹂。
DVM和JVM的區(qū)別
-
執(zhí)行的字節(jié)碼不同
- JAVA虛擬機(jī)運(yùn)行的是JAVA字節(jié)碼算凿,Dalvik虛擬機(jī)運(yùn)行的是Dalvik字節(jié)碼
JVM: .java -> javac -> .class -> jar -> .jar DVM: .java -> javac -> .class -> dx.bat -> .dex
- Dalvik可執(zhí)行文件體積更小
一般情況下凳谦,Java類(lèi)文件中包含多個(gè)不同的方法簽名忆畅,如果其他的類(lèi)文件引用該類(lèi)文件中的方法,方法簽名也會(huì)被復(fù)制到其類(lèi)文件中尸执,也就是說(shuō)家凯,多個(gè)不同的類(lèi)會(huì)同時(shí)包含相同的方法簽名,同樣地如失,大量的字符串常量在多個(gè)類(lèi)文件中也被重復(fù)使用绊诲。這些冗余信息會(huì)直接增加文件的體積,同時(shí)也會(huì)嚴(yán)重影響虛擬機(jī)解析文件的效率褪贵。
安卓使用Dalvik虛擬機(jī)掂之,SDK中有個(gè)dx工具負(fù)責(zé)將JAVA字節(jié)碼轉(zhuǎn)換為Dalvik字節(jié)碼,dx工具對(duì)JAVA類(lèi)文件重新排列脆丁,將所有JAVA類(lèi)文件中的常量池分解世舰,消除其中的冗余信息,重新組合形成一個(gè)常量池偎快,所有的類(lèi)文件共享同一個(gè)常量池冯乘,使得相同的字符串、常量在DEX文件中只出現(xiàn)一次晒夹,從而減小了文件的體積。
-
基于的架構(gòu)不同
Dvm基于寄存器姊氓,所以它的指令是二地址和三地址混合丐怯,指令中指明了操作數(shù)的地址;jvm基于棧翔横,它的指令是零地址读跷,指令的操作數(shù)對(duì)象默認(rèn)是操作數(shù)棧中的幾個(gè)位置。但基于寄存器的指令由于需要指定源地址和目標(biāo)地址禾唁,因此需要占用更多的指令空間效览。Java虛擬機(jī)基于棧架構(gòu)无切。程序在運(yùn)行時(shí)虛擬機(jī)需要頻繁的從棧上讀取或?qū)懭霐?shù)據(jù),這個(gè)過(guò)程需要更多的指令分派與內(nèi)存訪問(wèn)次數(shù)丐枉, 會(huì)耗費(fèi)不少CPU時(shí)間哆键, 對(duì)千像手機(jī)設(shè)備資源有限的設(shè)備來(lái)說(shuō), 這是相當(dāng)大的一筆開(kāi)銷(xiāo)瘦锹。Dalvik 虛擬機(jī)基于寄存器架構(gòu)籍嘹。數(shù)據(jù)的訪問(wèn)通過(guò)寄存器間直接傳遞, 這樣的訪問(wèn)方式比基千棧方式要快很多弯院。
Dalvik堆
Dalvik虛擬機(jī)用來(lái)分配對(duì)象的堆劃分為兩部分辱士,一部分叫做Active Heap,另一部分叫做Zygote Heap听绳。Android系統(tǒng)啟動(dòng)后颂碘,會(huì)有一個(gè)Zygote進(jìn)程創(chuàng)建第一個(gè)Dalvik虛擬機(jī),它只維護(hù)了一個(gè)堆椅挣。以后啟動(dòng)的所有應(yīng)用程序進(jìn)程是被Zygote進(jìn)程fork出來(lái)的凭涂,并都持有一個(gè)自己的Dalvik虛擬機(jī)。在創(chuàng)建應(yīng)用程序的過(guò)程中贴妻,Dalvik虛擬機(jī)采用COW策略復(fù)制Zygote進(jìn)程的地址空間切油。
當(dāng)創(chuàng)建第一個(gè)應(yīng)用程序進(jìn)程時(shí),會(huì)將已經(jīng)使用了的那部分堆內(nèi)存劃分為一部分名惩,還沒(méi)有使用的堆內(nèi)存劃分為另外一部分澎胡。前者就稱(chēng)為Zygote堆,后者就稱(chēng)為Active堆娩鹉。這樣只需把zygote堆中的內(nèi)容復(fù)制給應(yīng)用程序進(jìn)程就可以了攻谁。以后無(wú)論是Zygote進(jìn)程,還是應(yīng)用程序進(jìn)程弯予,當(dāng)它們需要分配對(duì)象的時(shí)候戚宦,都在Active堆上進(jìn)行。這樣就可以使得Zygote堆盡可能少地被執(zhí)行寫(xiě)操作锈嫩,因而就可以減少執(zhí)行寫(xiě)時(shí)拷貝的操作受楼。在Zygote堆里面分配的對(duì)象其實(shí)主要就是Zygote進(jìn)程在啟動(dòng)過(guò)程中預(yù)加載的類(lèi)、資源和對(duì)象了呼寸。這意味著這些預(yù)加載的類(lèi)艳汽、資源和對(duì)象可以在Zygote進(jìn)程和應(yīng)用程序進(jìn)程中做到長(zhǎng)期共享。這樣既能減少拷貝操作对雪,還能減少對(duì)內(nèi)存的需求河狐。Dalvik虛擬機(jī)進(jìn)行部分垃圾收集時(shí),實(shí)際上就是只收集在Active堆上分配的對(duì)象。
Art虛擬機(jī)
為了區(qū)分Art虛擬機(jī)和Dalvik虛擬機(jī)馋艺,需要先介紹下面兩個(gè)概念栅干。
JIT
JIT(Just-in-time Compilation,即時(shí)編譯)捐祠,又稱(chēng)為動(dòng)態(tài)編譯碱鳞,是一種通過(guò)在運(yùn)行時(shí)將字節(jié)碼翻譯為機(jī)器碼的技術(shù),使得程序的執(zhí)行速度更快雏赦。
在JVM中劫笙,javac將源程序編譯成java字節(jié)碼,JVM通過(guò)逐條解釋將字節(jié)碼翻譯成對(duì)應(yīng)的機(jī)器指令星岗,逐條讀入填大,逐條解釋翻譯,比較慢俏橘;為了提升速度允华,當(dāng)App運(yùn)行時(shí),每當(dāng)遇到一個(gè)新類(lèi)寥掐,JIT編譯器就會(huì)對(duì)這個(gè)類(lèi)進(jìn)行編譯靴寂,經(jīng)過(guò)編譯后的代碼,會(huì)被優(yōu)化成相當(dāng)精簡(jiǎn)的原生型指令碼(即native code)召耘,這樣在下次執(zhí)行到相同邏輯的時(shí)候百炬,速度就會(huì)更快。
但是污它,有一點(diǎn)需要注意剖踊,dex字節(jié)碼翻譯成本地機(jī)器碼是發(fā)生在應(yīng)用程序的運(yùn)行過(guò)程中的,并且應(yīng)用程序每一次重新運(yùn)行的時(shí)候衫贬,都要做重做這個(gè)翻譯工作德澈,每次重新打開(kāi)App,都需要JIT編譯固惯。AOT
ART的策略與Dalvik不同梆造,在ART 環(huán)境中,應(yīng)用在第一次安裝的時(shí)候葬毫,字節(jié)碼就會(huì)預(yù)先編譯成機(jī)器碼镇辉,使其成為真正的本地應(yīng)用。APK在安裝的時(shí)候供常,打包在里面的classes.dex文件會(huì)被工具dex2oat翻譯成本地機(jī)器指令摊聋,最終得到一個(gè)ELF格式的oat文件。
這樣可以保證以后每次打開(kāi)應(yīng)用栈暇,執(zhí)行的都是本地機(jī)器碼。去除了運(yùn)行時(shí)的解釋執(zhí)行箍镜,效率更高源祈,啟動(dòng)更快煎源。-
ART和Dalvik的區(qū)別
- ART需要應(yīng)用程序在安裝時(shí),就把程序代碼轉(zhuǎn)換成機(jī)器語(yǔ)言香缺,所以這會(huì)消耗掉更多的存儲(chǔ)空間手销,但消耗掉空間的增幅通常不會(huì)超過(guò)應(yīng)用代碼包大小的20%
- 由于有了一個(gè)轉(zhuǎn)碼的過(guò)程,所以應(yīng)用安裝時(shí)間難免會(huì)延長(zhǎng)
參考文章: