從JVM到Dalivk再到ART(class,dex,odex,vdex,ELF)

現(xiàn)在市面上的 Android 手機(jī)大部分都是運(yùn)行的是ART虛擬機(jī)了。還記得自己一部 Android手機(jī)(HuaweiG520)烈掠,Android4.1 系統(tǒng)。那時(shí)候還是沒有 ART虛擬機(jī) 的缸托。作為Android開發(fā)者左敌,我們應(yīng)該對(duì) Android 的發(fā)展歷史有些了解為什么 Android 會(huì)經(jīng)歷這么多的變化。Android 是先有 JVM 然后是 Dalvik 俐镐,接著是現(xiàn)在的 ART虛擬機(jī) 矫限。那么他們之間有什么關(guān)系呢?

Dalvik和ART

JVM就不用講述了大家都有了解,不了解的參見JVM百度百科叼风。

DalvikGoogle 公司自己設(shè)計(jì)用于 Android 平臺(tái)的虛擬機(jī)取董,是 Google 等廠商合作開發(fā)的 Android 移動(dòng)設(shè)備平臺(tái)的核心組成部分之一。它可以支持已轉(zhuǎn)換為 .dex 格式的 Java 應(yīng)用程序的運(yùn)行咬扇,.dex 格式是專為Dalvik 設(shè)計(jì)的一種壓縮格式甲葬,適合內(nèi)存和處理器速度有限的系統(tǒng)。

Dalvik和JVM的主要區(qū)別

首先通過介紹 Dalvik 的時(shí)候我們就知道 Dalvik 運(yùn)行的是 dex 文件懈贺,而JVM 運(yùn)行的是 class 文件经窖。

Dalvik VM 是基于寄存器的架構(gòu),而 JVM 是棧機(jī)梭灿。所以 Dalvik VM 的好處是可以做到更好的提前優(yōu)化(ahead-of-time optimization)画侣。 另外基于寄存器架構(gòu)的VM執(zhí)行起來更快,但是代價(jià)是更大的代碼長(zhǎng)度堡妒。

基于寄存器架構(gòu)的虛擬機(jī)有這么多的好處配乱,為什么之前設(shè)計(jì)JAVA的程序員沒有采用呢,而是采用現(xiàn)在基于棧的架構(gòu)開發(fā)的呢皮迟?

因?yàn)榛跅5奶摂M機(jī)也有它的優(yōu)點(diǎn)搬泥,它不對(duì) host 平臺(tái)的 寄存器數(shù)量 做假設(shè),有利于移植到不懂的平臺(tái)伏尼,這也符合的Java跨平臺(tái)的特點(diǎn)忿檩。而Dalvik 虛擬機(jī)則不關(guān)心這些奄抽,因?yàn)樗緛砭褪菫?ARM 這樣的多寄存器平臺(tái)設(shè)計(jì)的搔课,另外 Dalvik 被移植到 x86 機(jī)器上,即使 x86 這種寄存器少的平臺(tái)币旧,寄存器架構(gòu)的虛擬機(jī)也可以運(yùn)行辨图。

一般來說,基于堆棧的機(jī)器必須使用指令才能從堆棧上的加載和操作數(shù)據(jù),因此,相對(duì)基于寄存器的機(jī)器班套,它們需要更多的指令才能實(shí)現(xiàn)相同的性能。但是基于寄存器機(jī)器上的指令必須經(jīng)過編碼,因此,它們的指令往往更大故河。

public class Demo {
    public static void foo() {
        int a = 1;
        int b = 2;
        int c = (a + b) * 5;
     } 
}

我們可以查看Demo.java在JVM中的class和Dalvik的dex字節(jié)碼文件:
詳見:使用dx將class轉(zhuǎn)dex總結(jié)

bytecode

想要了解更多:基于棧的虛擬機(jī) VS 基于寄存器的虛擬機(jī)

Dalvik在JVM上的優(yōu)化

  • 在編譯時(shí)提前優(yōu)化代碼而不是等到運(yùn)行時(shí)
  • 虛擬機(jī)很小吱韭,使用的空間也小忧勿;被設(shè)計(jì)來滿足可高效運(yùn)行多種虛擬機(jī)實(shí)例杉女。
  • 常量池已被修改為只使用32位的索引,以簡(jiǎn)化解釋器
  • 標(biāo)準(zhǔn)Java字節(jié)碼實(shí)行8位堆棧指令,Dalvik使用16位指令集直接作用于局部變量鸳吸。局部變量通常來自4位的“虛擬寄存器”區(qū)。這樣減少了Dalvik的指令計(jì)數(shù)速勇,提高了翻譯速度晌砾。

Dalivk進(jìn)化之ART

2014年6月25日,Android L 正式亮相于召開的谷歌I/O大會(huì)烦磁,Android L 改動(dòng)幅度較大养匈,谷歌將直接刪除 Dalvik 哼勇,代替它的是傳聞已久的 ART。在在Android系統(tǒng)4.4 提出呕乎,在 Android5.0之后完全棄用 dalvik 全部采用 art為執(zhí)行環(huán)境积担。

ART( Android Runtime

ART 的機(jī)制與 Dalvik 不同。在 Dalvik 下猬仁,應(yīng)用每次運(yùn)行的時(shí)候帝璧,字節(jié)碼都需要通過即時(shí)編譯器(just in time ,JIT)轉(zhuǎn)換為機(jī)器碼湿刽,這會(huì)拖慢應(yīng)用的運(yùn)行效率的烁,而在ART 環(huán)境中,應(yīng)用在第一次安裝的時(shí)候诈闺,字節(jié)碼就會(huì)預(yù)先編譯成機(jī)器碼渴庆,使其成為真正的本地應(yīng)用。這個(gè)過程叫做預(yù)編譯(AOT,Ahead-Of-Time)雅镊。這樣的話襟雷,應(yīng)用的啟動(dòng)(首次)和執(zhí)行都會(huì)變得更加快速。

ART的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 系統(tǒng)性能的顯著提升仁烹。
  • 應(yīng)用啟動(dòng)更快耸弄、運(yùn)行更快、體驗(yàn)更流暢晃危、觸感反饋更及時(shí)叙赚。
  • 更長(zhǎng)的電池續(xù)航能力。
  • 支持更低的硬件僚饭。

缺點(diǎn):

  • 機(jī)器碼占用的存儲(chǔ)空間更大震叮,字節(jié)碼變?yōu)闄C(jī)器碼之后,可能會(huì)增加10%-20(不過在應(yīng)用包中鳍鸵,可執(zhí)行的代碼常常只是一部分苇瓣。比如最新的 Google+ APK 是 28.3 MB,但是代碼只有 6.9 MB偿乖。)
  • 應(yīng)用的安裝時(shí)間會(huì)變長(zhǎng)击罪。

class、dex贪薪、odex媳禁、ELF相愛相殺

從執(zhí)行文件上面進(jìn)行分析的話,JVM 對(duì)應(yīng) class 文件画切,Dalivk 對(duì)應(yīng) odex 文件竣稽,而 ART 對(duì)應(yīng) oat 文件。

工具:javac, dx
.java——>.class——->.dex
.java 文件經(jīng)過 javac 編譯器生成 .class 字節(jié)碼 再經(jīng)過。dx 工具生成 .dex 毫别。

為了在 JVM 優(yōu)化出一個(gè) Dalivk 虛擬機(jī)娃弓,所以把 JVM 運(yùn)行的 class 文件進(jìn)行打包優(yōu)化為 dex 文件,但其本質(zhì)還是和 class 文件一樣屬于字節(jié)碼文件岛宦。但是為了每次啟動(dòng)時(shí)都去掉從字節(jié)碼到機(jī)器碼的編譯過程台丛,Google 又從 Dalivk 中優(yōu)化出了 ART,在其安裝應(yīng)用的時(shí)候?qū)?dex 文件進(jìn)行預(yù)處理生成可執(zhí)行的 oat 文件砾肺。

JIT的引入

據(jù)說 Android 2.2 的虛擬機(jī) dalvik 使用了 JIT 技術(shù)挽霉,使其運(yùn)行速度快了5倍。

dalvik 解釋并執(zhí)行程序债沮,JIT 技術(shù)主要是對(duì)多次運(yùn)行的代碼進(jìn)行編譯炼吴,當(dāng)再次調(diào)用時(shí)使用編譯之后的機(jī)器碼,而不是每次都解釋疫衩,以節(jié)約時(shí)間硅蹦。5倍是測(cè)試程序測(cè)出的值,并不是說程序運(yùn)行速度也能達(dá)到5倍闷煤,這是因?yàn)闇y(cè)試程序有很多的重復(fù)調(diào)用和循環(huán)童芹,而一般程序主要是順序執(zhí)行的,而且它是一邊運(yùn)行鲤拿,一邊編譯假褪,一開始的時(shí)候提速不多,所以真正運(yùn)行程序速度提高不是特別明顯近顷。

每啟動(dòng)一個(gè)應(yīng)用程序生音,都會(huì)相應(yīng)地啟動(dòng)一個(gè) dalvik 虛擬機(jī),啟動(dòng)時(shí)會(huì)建立JIT 線程窒升,一直在后臺(tái)運(yùn)行缀遍。當(dāng)某段代碼被調(diào)用時(shí),虛擬機(jī)會(huì)判斷它是否需要編譯成機(jī)器碼饱须,如果需要域醇,就做一個(gè)標(biāo)記,JIT 線程不斷判斷此標(biāo)記蓉媳,如果發(fā)現(xiàn)被設(shè)定就把它編譯成機(jī)器碼譬挚,并將其機(jī)器碼地址及相關(guān)信息放入 entry table 中,下次執(zhí)行到此就跳到機(jī)器碼段執(zhí)行酪呻,而不再解釋執(zhí)行减宣,從而提高速度。

odex(optimized dex)

因?yàn)?apk 實(shí)際為 zip 壓縮包玩荠,虛擬機(jī)每次加載都需要從 apk 中讀取classes.dex 文件蚪腋,這樣會(huì)耗費(fèi)很多的時(shí)間丰歌,而如果采用了 odex 方式優(yōu)化的 dex 文件姨蟋,他包含了加載 dex 必須的依賴庫(kù)文件列表屉凯,只需要直接加載而不需要再去解析。

Android N 之前眼溶,對(duì)于在 dalvik 環(huán)境中 使用 dexopt 來對(duì) dex 字節(jié)碼進(jìn)行優(yōu)化生成 odex 文件最終存在手機(jī)的 data/dalvik-cache 目錄下悠砚,最后把 apk 文件中的 dex 文件刪除。

Android O 之后堂飞,odex 是從 vdex 這個(gè)文件中 提取了部分模塊生成的一個(gè)新的可執(zhí)行二進(jìn)制碼文件 灌旧, odexvdex 中提取后,vdex 的大小就減少了绰筛。

  • 第一次開機(jī)就會(huì)生成在 /system/app/<packagename>/oat/
  • 在系統(tǒng)運(yùn)行過程中枢泰,虛擬機(jī)將其 從 /system/appcopy/data/davilk-cache/ 下;
  • odex + vdex = apk 的全部源碼 (vdex 并不是獨(dú)立于 odex 的文件 odex + vdex 才代表一個(gè) apk );

AOT(Ahead-of-time)

ART 推出了預(yù)先 (AOT) 編譯,可提高應(yīng)用的性能铝噩。ART 還具有比 Dalvik 更嚴(yán)格的安裝時(shí)驗(yàn)證衡蚂。在安裝時(shí),ART 使用設(shè)備自帶的 dex2oat 工具來編譯應(yīng)用骏庸。該實(shí)用工具接受 DEX 文件作為輸入毛甲,并針對(duì)目標(biāo)設(shè)備生成已編譯應(yīng)用的可執(zhí)行文件。之后打開 App 的時(shí)候具被,不需要額外的翻譯工作玻募,直接使用本地機(jī)器碼運(yùn)行,因此運(yùn)行速度提高一姿。

AOTart 的核心七咧,oat 文件包含 oatdataoatexec。前者包含 dex 文件內(nèi)容叮叹,后者包含生成的本地機(jī)器指令艾栋,從這里看出 oat 文件回會(huì)比 dex 文件占用更大的存儲(chǔ)空間。

因?yàn)?oat 文件包含生成的本地機(jī)器指令進(jìn)而可以直接運(yùn)行衬横,它同樣保存在手機(jī)的 data/dalvik-cache 目錄下 PMS(PackgetManagerService)—>installd(守護(hù)進(jìn)程)——>dex2oat(/system/bin/dex2oat) 裹粤。注意存放在 data/dalvik-cache 目錄下的后綴名都仍為 .dex 前者其實(shí)表示一個(gè)優(yōu)化過的 .dex 文件 后者為 .art 文件。

push 一個(gè)新的 apk 文件覆蓋之前 /system/appapk 文件蜂林,會(huì)觸發(fā) PKMS 掃描時(shí)下發(fā) force_dex flag 遥诉,強(qiáng)行生成新的 vdex文件 ,覆蓋之前的vdex 文件噪叙,由于某種機(jī)制矮锈,這個(gè)新 vdex 文件會(huì) copy/data/dalvik-cache/ 下,于是 art 文件也變化了睁蕾。

混合運(yùn)行時(shí)

Android N 開發(fā)者預(yù)覽版包含了一個(gè)混合模式的運(yùn)行時(shí)苞笨。應(yīng)用在安裝時(shí)不做編譯债朵,而是解釋字節(jié)碼,所以可以快速啟動(dòng)瀑凝。ART中有一種新的序芦、更快的解釋器,通過一種新的 JIT 完成粤咪,但是這種 JIT 的信息不是持久化的谚中。取而代之的是,代碼在執(zhí)行期間被分析寥枝,分析結(jié)果保存起來宪塔。然后,當(dāng)設(shè)備空轉(zhuǎn)和充電的時(shí)候囊拜,ART 會(huì)執(zhí)行針對(duì)“熱代碼”進(jìn)行的基于分析的編譯某筐,其他代碼不做編譯。為了得到更優(yōu)的代碼冠跷,ART 采用了幾種技巧包括深度內(nèi)聯(lián)南誊。

對(duì)同一個(gè)應(yīng)用可以編譯數(shù)次,或者找到變“熱”的代碼路徑或者對(duì)已經(jīng)編譯的代碼進(jìn)行新的優(yōu)化蔽莱,這取決于分析器在隨后的執(zhí)行中的分析數(shù)據(jù)弟疆。這個(gè)步驟仍被簡(jiǎn)稱為 AOT,可以理解為“全時(shí)段的編譯”(All-Of-the-Time compilation)盗冷。

這種混合使用 AOT怠苔、解釋、JIT 的策略的全部?jī)?yōu)點(diǎn)如下仪糖。

  • 即使是大應(yīng)用柑司,安裝時(shí)間也能縮短到幾秒;
  • 系統(tǒng)升級(jí)能更快地安裝,因?yàn)椴辉傩枰獌?yōu)化這一步;
  • 應(yīng)用的內(nèi)存占用更小锅劝,有些情況下可以降低 50%;
  • 改善了性能;
  • 更低的電池消耗;

vdex

官網(wǎng)回答:ART的運(yùn)作方式
dex2oat 工具接受一個(gè) APK 文件攒驰,并生成一個(gè)或多個(gè)編譯工件文件,然后運(yùn)行時(shí)將會(huì)加載這些文件故爵。文件的個(gè)數(shù)玻粪、擴(kuò)展名和名稱會(huì)因版本而異。
在 Android O 版本中诬垂,將會(huì)生成以下文件:

  • .vdex:其中包含 APK 的未壓縮 DEX 代碼劲室,另外還有一些旨在加快驗(yàn)證速度的元數(shù)據(jù)。
  • .odex:其中包含 APK 中已經(jīng)過 AOT 編譯的方法代碼结窘。
  • .art (optional):其中包含 APK 中列出的某些字符串和類的 ART 內(nèi)部表示很洋,用于加快應(yīng)用啟動(dòng)速度。
  • 第一次開機(jī)就會(huì)生成在 /system/app/<packagename>/oat/ 下隧枫;
  • 在系統(tǒng)運(yùn)行過程中喉磁,虛擬機(jī)將其 從 /system/appcopy/data/davilk-cache/ 下谓苟。

ELF文件

ELF(Executable and Linking Format)是一種對(duì)象文件的格式,用于定義不同類型的對(duì)象文件(Object files)中都放了什么東西协怒、以及都以什么樣的格式去放這些東西涝焙。它自最早在 System V系統(tǒng)上出現(xiàn)后,被 xNIX 世界所廣泛接受斤讥,作為缺省的二進(jìn)制文件格式來使用纱皆。可以說芭商,ELF 是構(gòu)成眾多 xNIX 系統(tǒng)的基礎(chǔ)之一。

apk安裝過程

大家都知道 apk 其實(shí)就是 zipapk 安裝過程其實(shí)就是解壓過程搀缠。
用戶應(yīng)用安裝涉及以下幾個(gè)目錄:

  • data/app 安裝目錄 安裝時(shí)會(huì)把 apk 文件 copy 到這里;
  • data/dalvik-cache 如上述描述中的存放.dex ( .odex 無論 davilkdex 還是 artoat 格式);
  • data/data/pkg/ 存放應(yīng)用程序的數(shù)據(jù);

Android5.1 版本下 oat 文件都以 .dex 文件在 data/dalvik-cache 目錄下:

dalvik-cache.jpeg

Android8.0 版本下 dex2oat 工具生成的三個(gè).art铛楣,.odex,.vdex文件都在 data/dalvik-cache 目錄下:

sogou-dalvik-cache-arm64.png

Android8.0 版本下搜狗輸入法在 data/app/com.sohu.inputmethod.sogou.xiaomi-JAKuH_Jhlk6Y36zKoTUN8Q== 目錄下:

sogou-data-app-xxxxx.jpg

Android8.0 版本下搜狗輸入法在 system/app/SogouInput 目錄下:

sogou-system-app-xxx.jpg

文中部分內(nèi)容摘自:
深入理解JVM-字節(jié)碼執(zhí)行引擎
知乎-Dalvik 虛擬機(jī)和 Sun JVM 在架構(gòu)和執(zhí)行方面有什么本質(zhì)區(qū)別艺普?
《Java虛擬機(jī)原理圖解》4.JVM機(jī)器指令集
Android[art]-Android dex簸州,odex,oat歧譬,vdex岸浑,art文件結(jié)構(gòu)學(xué)習(xí)總結(jié)
Android N 混合使用 AOT 編譯,解釋和 JIT 三種運(yùn)行時(shí)

修改歷史:
【第一次發(fā)布】2017.09.18 19:00
【第二次主要修改不oat瑰步、vdex和odex相關(guān)內(nèi)容】2020.04.02 22:00

文章到這里就全部講述完啦矢洲,若有其他需要交流的可以留言哦~!~缩焦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末读虏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子袁滥,更是在濱河造成了極大的恐慌盖桥,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件题翻,死亡現(xiàn)場(chǎng)離奇詭異揩徊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嵌赠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門塑荒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人猾普,你說我怎么就攤上這事袜炕。” “怎么了初家?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵偎窘,是天一觀的道長(zhǎng)乌助。 經(jīng)常有香客問我,道長(zhǎng)陌知,這世上最難降的妖魔是什么他托? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮仆葡,結(jié)果婚禮上赏参,老公的妹妹穿的比我還像新娘。我一直安慰自己沿盅,他們只是感情好把篓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腰涧,像睡著了一般韧掩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窖铡,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天疗锐,我揣著相機(jī)與錄音,去河邊找鬼费彼。 笑死滑臊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的箍铲。 我是一名探鬼主播雇卷,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼虹钮!你這毒婦竟也來了聋庵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤芙粱,失蹤者是張志新(化名)和其女友劉穎祭玉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體春畔,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脱货,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了律姨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片振峻。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖择份,靈堂內(nèi)的尸體忽然破棺而出扣孟,到底是詐尸還是另有隱情,我是刑警寧澤荣赶,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布凤价,位于F島的核電站鸽斟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏利诺。R本人自食惡果不足惜富蓄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慢逾。 院中可真熱鬧立倍,春花似錦、人聲如沸侣滩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)胜卤。三九已至疆导,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間葛躏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工悠菜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留舰攒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓悔醋,卻偏偏與公主長(zhǎng)得像摩窃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芬骄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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