Java 虛擬機(jī)、Art、Dalvik 他們的區(qū)別

1.JVM與DVM

1.概念

JVM的作用是把平臺無關(guān)的.class里面的字節(jié)碼翻譯成平臺相關(guān)的機(jī)器碼,來實(shí)現(xiàn)跨平臺。DVM就是安卓中使用的虛擬機(jī)。

Dalvik允許多個(gè)實(shí)例,每一個(gè)實(shí)例作為一個(gè)獨(dú)立的linux進(jìn)程執(zhí)行,可以防止一個(gè)程序的崩潰導(dǎo)致所有程序都崩潰。

2.區(qū)別
  • jvm通過解碼class文件來運(yùn)行程序;dvm則是dex文件。

dex文件是由多個(gè)class文件打包而成,一個(gè)dex文件方法數(shù)不能超過65535。

 JVM: .java -> javac -> .class -> jar -> .jar , 架構(gòu): 堆和棧的架構(gòu).
 DVM: .java -> javac -> .class -> dx.bat -> .dex , 架構(gòu): 寄存器(cpu上的一塊高速緩存)。

Dalvik字節(jié)碼中,變量會被復(fù)制給65536個(gè)可用寄存器中的任何一個(gè),直接訪問這些寄存器,而不是方位堆棧中的元素;
JVM字節(jié)碼中,變量會被壓入堆棧中進(jìn)行運(yùn)算;基于寄存器的方式在編譯的時(shí)候花費(fèi)的時(shí)間更短。這也是下面要說的。

  • dvm基于寄存器架構(gòu)(句柄引用),jvm基于棧架構(gòu)(指針引用)

dvm基于寄存器,所以它的指令是二地址和三地址混合,指令中指明了操作數(shù)的地址;jvm基于棧,它的指令是零地址,指令的操作數(shù)對象默認(rèn)是操作數(shù)棧中的幾個(gè)位置。但基于寄存器的指令由于需要指定源地址和目標(biāo)地址,因此需要占用更多的指令空間

dvm速度快!指令數(shù)小寄存器存取速度比棧快的多,dvm可以根據(jù)硬件實(shí)現(xiàn)最大的優(yōu)化,比較適合移動設(shè)備。JAVA虛擬機(jī)基于棧結(jié)構(gòu),程序在運(yùn)行時(shí)虛擬機(jī)需要頻繁的從棧上讀取寫入數(shù)據(jù),這個(gè)過程需要更多的指令分派與內(nèi)存訪問次數(shù),會耗費(fèi)很多CPU時(shí)間。

這樣帶來的結(jié)果就是dvm的指令數(shù)相對于jvm的指令數(shù)會小很多,jvm需要多條指令而dvm可能只需要一條指令。jvm基于棧帶來的好處是可以做的足夠簡單,真正的跨平臺,保證在低硬件條件下能夠正常運(yùn)行。而dvm操作平臺一般指明是ARM系統(tǒng),所以采取的策略有所不同。需要注意的是dvm基于寄存器,但是這也是個(gè)映射關(guān)系,如果硬件沒有足夠的寄存器,dvm將多出來的寄存器映射到內(nèi)存中

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

SDK中有個(gè)dx工具負(fù)責(zé)將JAVA字節(jié)碼轉(zhuǎn)換為Dalvik字節(jié)碼,將所有java文件中的常量池合并為一個(gè)常量池,使得相同的字符串和常量只在DEX文件中出現(xiàn)一次。

運(yùn)行時(shí),共享相同的類,這樣系統(tǒng)消耗會小很多,JVM機(jī)制中,打包后,他們都是完全獨(dú)立的程序,類都是單獨(dú)加載,單獨(dú)運(yùn)行;

3.jvm(參考)

當(dāng)啟動一個(gè)java程序,一個(gè)虛擬機(jī)實(shí)例也就誕生了。當(dāng)該程序關(guān)閉退出,這個(gè)虛擬機(jī)實(shí)例也就隨之消亡。

java內(nèi)部有兩種線程:守護(hù)線程和非守護(hù)線程。非守護(hù)線程就是我們所說的main方法;守護(hù)線程通常是由虛擬機(jī)自己使用,如執(zhí)行垃圾回收任務(wù)的線程。Java程序也可以把它創(chuàng)建的任何線程標(biāo)記為守護(hù)線程。只要還有非守護(hù)進(jìn)行在,這個(gè)java程序也在繼續(xù)進(jìn)行

虛擬機(jī)的結(jié)構(gòu)圖

每個(gè)Java虛擬機(jī)都有一個(gè)類裝載子系統(tǒng),它根據(jù)給定的全限定名來裝入類型(類或接口)。同樣,每個(gè)Java虛擬機(jī)都有一個(gè)執(zhí)行引擎,它負(fù)責(zé)執(zhí)行那些包含在被裝載類的方法中的指令。

每個(gè)Java虛擬機(jī)實(shí)例都有一個(gè)方法區(qū)以及一個(gè)堆,它們是由該虛擬機(jī)實(shí)例中所有的線程共享的。當(dāng)虛擬機(jī)裝載一個(gè)class文件時(shí),它會從這個(gè)class文件包含的二進(jìn)制數(shù)據(jù)中解析類型信息。然后把這些類型信息放到方法區(qū)中。當(dāng)程序運(yùn)行時(shí),虛擬機(jī)會把所有該程序在運(yùn)行時(shí)創(chuàng)建的對象都放到堆中

當(dāng)每一個(gè)新線程被創(chuàng)建時(shí),它都將得到它自己的PC寄存器(程序計(jì)數(shù)器)以及一個(gè)Java棧。如果線程正在執(zhí)行的是一個(gè)Java方法(非本地方法),那么PC寄存器的值將總是指向下一條將被執(zhí)行的指令,java棧存儲該線程中Java方法調(diào)用的狀態(tài)——包括它的局部變量,被調(diào)用時(shí)傳進(jìn)來的參數(shù)、返回值,以及運(yùn)算的中間結(jié)果等等。而本地方法調(diào)用的狀態(tài),則是以某種依賴于具體實(shí)現(xiàn)的方法存儲在本地方法棧中,也可能是在寄存器或者其他某些與特定實(shí)現(xiàn)相關(guān)的內(nèi)存區(qū)中。

Java虛擬機(jī)沒有寄存器,其指令集使用Java棧來存儲中間數(shù)據(jù)。Java棧是由許多棧幀(stack frame)組成的,一個(gè)棧幀包含一個(gè)Java方法調(diào)用的狀態(tài)。當(dāng)線程調(diào)用一個(gè)Java方法時(shí),虛擬機(jī)壓入一個(gè)新的棧幀到該線程的Java棧中,當(dāng)該方法返回時(shí),這個(gè)棧幀被從Java棧中彈出并拋棄。

虛擬機(jī)必須為每個(gè)被裝載的類型維護(hù)一個(gè)常量池。常量池就是該類型所用常量的一個(gè)有序集合,包括直接常量和對其他類型、字段和方法的符號引用。池中的數(shù)據(jù)項(xiàng)就像數(shù)組一樣是通過索引訪問的。因?yàn)槌A砍卮鎯α讼鄳?yīng)類型所用到的所有類型、字段和方法的符號引用,所以它在Java程序的動態(tài)連接中起著核心的作用。
創(chuàng)建對象就是通過常量池中對應(yīng)類的引用找到方法區(qū)中對應(yīng)類。

4.Dalvik

Dalvik將堆分成了Active堆和Zygote堆,Zygote堆是Zygote進(jìn)程在啟動的時(shí)候預(yù)加載的類、資源和對象,除此之外的所有對象都是存儲在Active堆中的。

Dalvik的gygote堆存放的預(yù)加載的類都是Android核心類和java運(yùn)行時(shí)庫,這部分內(nèi)容很少被修改,大多數(shù)情況父進(jìn)程和子進(jìn)程共享這塊內(nèi)存區(qū)域。通常垃圾回收重點(diǎn)對Active堆進(jìn)行回收操作,Dalvik為了對堆進(jìn)行更好的管理創(chuàng)建了一個(gè)Card Table、兩個(gè)Heap Bitmap和一個(gè)Mark Stack數(shù)據(jù)結(jié)構(gòu)。

許多GC實(shí)現(xiàn)都是在對象開頭的地方留一小塊空間給GC標(biāo)記用。Dalvik VM則不同,在進(jìn)行GC的時(shí)候會單獨(dú)申請一塊空間,以位圖的形式來保存整個(gè)堆上的對象的標(biāo)記,在GC結(jié)束后就釋放該空間。

Dalvik使用即時(shí)編譯(JIT),即是在程序運(yùn)行過程中進(jìn)行編譯。JIT會在運(yùn)行時(shí)分析應(yīng)用程序的代碼,識別哪些方法可以歸類為熱方法,這些方法會被JIT編譯器編譯成對應(yīng)的匯編代碼,然后存儲到代碼緩存中,以后調(diào)用這些方法時(shí)就不用解釋執(zhí)行了,可以直接使用代碼緩存中已編譯好的匯編代碼。

javac把程序源碼編譯成JAVA字節(jié)碼,JVM通過逐條解釋字節(jié)碼將其翻譯成對應(yīng)的機(jī)器指令,逐條讀入,逐條解釋翻譯,執(zhí)行速度必然比C/C++編譯后的可執(zhí)行二進(jìn)制字節(jié)碼程序慢,為了提高執(zhí)行速度,就引入了JIT技術(shù)

2.ART

與Dalvik不同,ART使用預(yù)編譯(AOT,Ahead-Of-Time)。也就是在APK運(yùn)行之前,就對其包含的Dex字節(jié)碼進(jìn)行翻譯,得到對應(yīng)的本地機(jī)器指令,于是就可以在運(yùn)行時(shí)直接執(zhí)行了。

ART應(yīng)用安裝的時(shí)候把dex中的字節(jié)碼將被編譯成本地機(jī)器碼,之后每次打開應(yīng)用,執(zhí)行的都是本地機(jī)器碼。去除了運(yùn)行時(shí)的解釋執(zhí)行,效率更高,啟動更快。

在Android系統(tǒng)啟動過程中創(chuàng)建的Zygote進(jìn)程利用ART運(yùn)行時(shí)導(dǎo)出的Java虛擬機(jī)接口創(chuàng)建ART虛擬機(jī)。APK在安裝的時(shí)候,打包在里面的classes.dex文件會被工具dex2oat翻譯成本地機(jī)器指令,最終得到一個(gè)ELF格式的oat文件。APK運(yùn)行時(shí),上述生成的oat文件會被加載到內(nèi)存中,并且ART虛擬機(jī)可以通過里面的oatdataoatexec段找到任意一個(gè)類的方法對應(yīng)的本地機(jī)器指令來執(zhí)行。 oat文件中的oatdata包含用來生成本地機(jī)器指令的dex文件,內(nèi)容oat文件中的oatexec包含有生成的本地機(jī)器指令

可以分配內(nèi)存的Space有三個(gè):Zygote Space、Allocation Space和Large Object Space。實(shí)際上應(yīng)用運(yùn)行的時(shí)候能夠分配內(nèi)存也就Allocation 和 Large Object Space兩個(gè)。

image

ART優(yōu)點(diǎn):
①系統(tǒng)性能顯著提升,每次啟動執(zhí)行的時(shí)候,都可以直接運(yùn)行,因此運(yùn)行效率會提高。
②應(yīng)用啟動更快、運(yùn)行更快、體驗(yàn)更流暢、觸感反饋更及時(shí)
③續(xù)航能力提升,因?yàn)閼?yīng)用程序每次運(yùn)行時(shí)不用重復(fù)編譯了,從而減少了 CPU 的使用頻率,降低了能耗。
④支持更低的硬件

ART缺點(diǎn)
①更大的存儲空間占用,可能增加10%-20%(字節(jié)碼變?yōu)闄C(jī)器碼之后,可能會增加10%-20%)
②更長的應(yīng)用安裝時(shí)間,應(yīng)用在第一次安裝的時(shí)候,字節(jié)碼就會預(yù)編譯(AOT)成機(jī)器碼,這樣的話,雖然設(shè)備和應(yīng)用的首次啟動(安裝慢了)會變慢

4.android7.0\7.1

android7.0\7.1的ART引入了全新的Hybrid模式(Interpreter + JIT + AOT)

  • 與前面不同,app在安裝時(shí)不進(jìn)行編譯,所以安裝速度會更快。
  • 在運(yùn)行App時(shí), 先走解釋器, 然后熱點(diǎn)函數(shù)會被識別,并被JIT進(jìn)行編譯, 存儲在jit code cache, 并產(chǎn)生profile文件(記錄熱點(diǎn)函數(shù)信息)。
  • 等手機(jī)進(jìn)入充電和空閑狀態(tài)下, 系統(tǒng)會每隔一段時(shí)間掃描App目錄下profile文件,并執(zhí)行AOT編譯(Google官方稱之為profile-guided compilation)。
  • 不論是jit編譯的binary code, 還是AOT編譯的binary code, 它們之間的性能差別不大, 因?yàn)樗鼈兪褂猛粋€(gè)optimizing compiler進(jìn)行編譯。

這樣的優(yōu)點(diǎn)是:App安裝速度快,占用存儲少(只編譯熱點(diǎn)函數(shù))。

缺點(diǎn)是:前幾次運(yùn)行會較慢, 只有用戶操作得次數(shù)越多,jit 和AOT編譯后, 性能才會跟上來。

后記

垃圾回收機(jī)制也是很重要的一環(huán),但這個(gè)能說的太多了。
參考:

JVM、Dalvik VM和ART虛擬機(jī)之間的區(qū)別

Dalvik虛擬機(jī)簡要介紹和學(xué)習(xí)計(jì)劃

JAVA虛擬機(jī)、Dalvik虛擬機(jī)和ART虛擬機(jī)簡要對比

JAVA虛擬機(jī)的生命周期

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,258評論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,234評論 2 375

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