JAVA虛擬機、Dalvik虛擬機和ART虛擬機簡要對比

JVM

什么是JVM

JVM本質(zhì)上就是一個軟件,是計算機硬件的一層軟件抽象,在這之上才能夠運行Java程序,JAVA在編譯后會生成類似于匯編語言的JVM字節(jié)碼,與C語言編譯后產(chǎn)生的匯編語言不同的是,C編譯成的匯編語言會直接在硬件上跑,但JAVA編譯后生成的字節(jié)碼是在JVM上跑,需要由JVM把字節(jié)碼翻譯成機器指令,才能使JAVA程序跑起來。

JVM運行在操作系統(tǒng)上,屏蔽了底層實現(xiàn)的差異,從而有了JAVA吹噓的平臺獨立性和Write Once Run Anywhere。根據(jù)JVM規(guī)范實現(xiàn)的具體虛擬機有幾十種,主流的JVM包括Hotspot、Jikes RVM等,都是用C/C++和匯編編寫的,每個JRE編譯的時候針對每個平臺編譯,因此下載JRE(JVM、Java核心類庫和支持文件)的時候是分平臺的,

作用

JVM的作用是把平臺無關(guān)的.class里面的字節(jié)碼翻譯成平臺相關(guān)的機器碼,來實現(xiàn)跨平臺。

什么是DVM

JVM是Java Virtual Machine,而DVM就是Dalvik Virtual Machine,是安卓中使用的虛擬機。

作用

所有安卓程序都運行在安卓系統(tǒng)進程里,每個進程對應著一個Dalvik虛擬機實例。他們都提供了對象生命周期管理、堆棧管理、線程管理、安全和異常管理以及垃圾回收等重要功能,各自擁有一套完整的指令系統(tǒng),以下簡要對比兩種虛擬機的不同。

JVM 與 DVM 對比

JAVA虛擬機運行的是JAVA字節(jié)碼,Dalvik虛擬機運行的是Dalvik字節(jié)碼

JAVA程序經(jīng)過編譯,生成JAVA字節(jié)碼保存在class文件中,JVM通過解碼class文件中的內(nèi)容來運行程序。而DVM
運行的是Dalvik字節(jié)碼,所有的Dalvik字節(jié)碼由JAVA字節(jié)碼轉(zhuǎn)換而來,并被打包到一個DEX(Dalvik Executable)可執(zhí)行文件中,DVM通過解釋DEX文件來執(zhí)行這些字節(jié)碼。

Dalvik可執(zhí)行文件體積更小

以下是JVM規(guī)范中以C的數(shù)據(jù)結(jié)構(gòu)表達的class文件結(jié)構(gòu),class文件被虛擬機加載到內(nèi)存中后便是這樣

image.png

class文件中包含多個不同的方法簽名,如果A類文件引用B類文件中的方法,方法簽名也會被復制到A類文件中(在虛擬機加載類的連接階段將會使用該簽名鏈接到B類的對應方法),也就是說,多個不同的類會同時包含相同的方法簽名,同樣地,大量的字符串常量在多個類文件中也被重復使用,這些冗余信息會直接增加文件的體積,而JVM在把描述類的數(shù)據(jù)從class文件加載到內(nèi)存時,需要對數(shù)據(jù)進行校驗、轉(zhuǎn)換解析和初始化,最終才形成可以被虛擬機直接使用的JAVA類型,因為大量的冗余信息,會嚴重影響虛擬機解析文件的效率。

為了減小執(zhí)行文件的體積,安卓使用Dalvik虛擬機,SDK中有個dx工具負責將JAVA字節(jié)碼轉(zhuǎn)換為Dalvik字節(jié)碼,dx工具對JAVA類文件重新排列,將所有JAVA類文件中的常量池分解,消除其中的冗余信息,重新組合形成一個常量池,所有的類文件共享同一個常量池,使得相同的字符串、常量在DEX文件中只出現(xiàn)一次,從而減小了文件的體積。

dx工具的轉(zhuǎn)換過程和DEX文件的結(jié)構(gòu)如下圖所示:


image.png

JVM基于棧,DVM基于寄存器

JAVA虛擬機基于棧結(jié)構(gòu),程序在運行時虛擬機需要頻繁的從棧上讀取寫入數(shù)據(jù),這個過程需要更多的指令分派與內(nèi)存訪問次數(shù),會耗費很多CPU時間。

Dalvik虛擬機基于寄存器架構(gòu),數(shù)據(jù)的訪問通過寄存器間直接傳遞,這樣的訪問方式比基于棧方式要快很多。

public class Hello {
    public int foo(int a, int b) {
        return (a + b) * (a - b);
    }
 
    public static void main(String[] args) {
        Hello t = new Hello();
        System.out.print(t.foo(5, 3));
    }
}

以這段代碼中的foo方法為例,編譯成class文件后,反編譯class文件查看JAVA字節(jié)碼:

Code:
         0: iload_1
         1: iload_2
         2: iadd
         3: iload_1
         4: iload_2
         5: isub
         6: imul
         7: ireturn

同樣代碼的foo方法,編譯生成dex文件后,查看Dalvik字節(jié)碼:

         0000: add-int  v0, v3, v4
         0002: sub-int  v1, v3, v4
         0004: mul-int/2addr  v0, v1
         0005: return  v0

由以上字節(jié)碼對比,代碼指令減少了,執(zhí)行速度當然也會更快。

下圖為兩種虛擬機分別執(zhí)行自己的字節(jié)碼的過程對比:


image.png

什么是ART

首先了解 JIT(Just In Time,即時編譯技術(shù))AOT (Ahead Of Time,預編譯技術(shù))兩種編譯模式。
JIT以JVM為例,javac把程序源碼編譯成JAVA字節(jié)碼,JVM通過逐條解釋字節(jié)碼將其翻譯成對應的機器指令,逐條讀入,逐條解釋翻譯,執(zhí)行速度必然比C/C++編譯后的可執(zhí)行二進制字節(jié)碼程序慢,為了提高執(zhí)行速度,就引入了JIT技術(shù),JIT會在運行時分析應用程序的代碼,識別哪些方法可以歸類為熱方法,這些方法會被JIT編譯器編譯成對應的匯編代碼,然后存儲到代碼緩存中,以后調(diào)用這些方法時就不用解釋執(zhí)行了,可以直接使用代碼緩存中已編譯好的匯編代碼。這能顯著提升應用程序的執(zhí)行效率。(安卓Dalvik虛擬機在2.2中增加了JIT)

相對的AOT就是指C/C++這類語言,編譯器在編譯時直接將程序源碼編譯成目標機器碼,運行時直接運行機器碼。

Dalvik虛擬機執(zhí)行的是dex字節(jié)碼,ART虛擬機執(zhí)行的是本地機器碼

Dalvik執(zhí)行的是dex字節(jié)碼,依靠JIT編譯器去解釋執(zhí)行,運行時動態(tài)地將執(zhí)行頻率很高的dex字節(jié)碼翻譯成本地機器碼,然后在執(zhí)行,但是將dex字節(jié)碼翻譯成本地機器碼是發(fā)生在應用程序的運行過程中,并且應用程序每一次重新運行的時候,都要重新做這個翻譯工作,因此,即使采用了JIT,Dalvik虛擬機的總體性能還是不能與直接執(zhí)行本地機器碼的ART虛擬機相比。

安卓運行時從Dalvik虛擬機替換成ART虛擬機,并不要求開發(fā)者重新將自己的應用直接編譯成目標機器碼,也就是說,應用程序仍然是一個包含dex字節(jié)碼的apk文件。所以在安裝應用的時候,dex中的字節(jié)碼將被編譯成本地機器碼,之后每次打開應用,執(zhí)行的都是本地機器碼。移除了運行時的解釋執(zhí)行,效率更高,啟動更快。(安卓在4.4中發(fā)布了ART運行時)

ART優(yōu)點:

  • 系統(tǒng)性能顯著提升
  • 應用啟動更快、運行更快、體驗更流暢、觸感反饋更及時
  • 續(xù)航能力提升
  • 支持更低的硬件

ART缺點

  • 更大的存儲空間占用,可能增加10%-20%
  • 更長的應用安裝時間

總的來說ART就是空間換時間

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容