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

現在市面上的 Android 手機大部分都是運行的是ART虛擬機了。還記得自己一部 Android手機(HuaweiG520),Android4.1 系統。那時候還是沒有 ART虛擬機 的。作為Android開發者,我們應該對 Android 的發展歷史有些了解為什么 Android 會經歷這么多的變化。Android 是先有 JVM 然后是 Dalvik ,接著是現在的 ART虛擬機 。那么他們之間有什么關系呢?

Dalvik和ART

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

DalvikGoogle 公司自己設計用于 Android 平臺的虛擬機,是 Google 等廠商合作開發的 Android 移動設備平臺的核心組成部分之一。它可以支持已轉換為 .dex 格式的 Java 應用程序的運行,.dex 格式是專為Dalvik 設計的一種壓縮格式,適合內存和處理器速度有限的系統。

Dalvik和JVM的主要區別

首先通過介紹 Dalvik 的時候我們就知道 Dalvik 運行的是 dex 文件,而JVM 運行的是 class 文件。

Dalvik VM 是基于寄存器的架構,而 JVM 是棧機。所以 Dalvik VM 的好處是可以做到更好的提前優化(ahead-of-time optimization)。 另外基于寄存器架構的VM執行起來更快,但是代價是更大的代碼長度。

基于寄存器架構的虛擬機有這么多的好處,為什么之前設計JAVA的程序員沒有采用呢,而是采用現在基于棧的架構開發的呢?

因為基于棧的虛擬機也有它的優點,它不對 host 平臺的 寄存器數量 做假設,有利于移植到不懂的平臺,這也符合的Java跨平臺的特點。而Dalvik 虛擬機則不關心這些,因為它本來就是為 ARM 這樣的多寄存器平臺設計的,另外 Dalvik 被移植到 x86 機器上,即使 x86 這種寄存器少的平臺,寄存器架構的虛擬機也可以運行。

一般來說,基于堆棧的機器必須使用指令才能從堆棧上的加載和操作數據,因此,相對基于寄存器的機器,它們需要更多的指令才能實現相同的性能。但是基于寄存器機器上的指令必須經過編碼,因此,它們的指令往往更大。

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

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

bytecode

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

Dalvik在JVM上的優化

  • 在編譯時提前優化代碼而不是等到運行時
  • 虛擬機很小,使用的空間也小;被設計來滿足可高效運行多種虛擬機實例。
  • 常量池已被修改為只使用32位的索引,以簡化解釋器
  • 標準Java字節碼實行8位堆棧指令,Dalvik使用16位指令集直接作用于局部變量。局部變量通常來自4位的“虛擬寄存器”區。這樣減少了Dalvik的指令計數,提高了翻譯速度。

Dalivk進化之ART

2014年6月25日,Android L 正式亮相于召開的谷歌I/O大會,Android L 改動幅度較大,谷歌將直接刪除 Dalvik ,代替它的是傳聞已久的 ART。在在Android系統4.4 提出,在 Android5.0之后完全棄用 dalvik 全部采用 art為執行環境。

ART( Android Runtime

ART 的機制與 Dalvik 不同。在 Dalvik 下,應用每次運行的時候,字節碼都需要通過即時編譯器(just in time ,JIT)轉換為機器碼,這會拖慢應用的運行效率,而在ART 環境中,應用在第一次安裝的時候,字節碼就會預先編譯成機器碼,使其成為真正的本地應用。這個過程叫做預編譯(AOT,Ahead-Of-Time)。這樣的話,應用的啟動(首次)和執行都會變得更加快速。

ART的優缺點

優點:

  • 系統性能的顯著提升。
  • 應用啟動更快、運行更快、體驗更流暢、觸感反饋更及時。
  • 更長的電池續航能力。
  • 支持更低的硬件。

缺點:

  • 機器碼占用的存儲空間更大,字節碼變為機器碼之后,可能會增加10%-20(不過在應用包中,可執行的代碼常常只是一部分。比如最新的 Google+ APK 是 28.3 MB,但是代碼只有 6.9 MB。)
  • 應用的安裝時間會變長。

class、dex、odex、ELF相愛相殺

從執行文件上面進行分析的話,JVM 對應 class 文件,Dalivk 對應 odex 文件,而 ART 對應 oat 文件。

工具:javac, dx
.java——>.class——->.dex
.java 文件經過 javac 編譯器生成 .class 字節碼 再經過。dx 工具生成 .dex

為了在 JVM 優化出一個 Dalivk 虛擬機,所以把 JVM 運行的 class 文件進行打包優化為 dex 文件,但其本質還是和 class 文件一樣屬于字節碼文件。但是為了每次啟動時都去掉從字節碼到機器碼的編譯過程,Google 又從 Dalivk 中優化出了 ART,在其安裝應用的時候將 dex 文件進行預處理生成可執行的 oat 文件。

JIT的引入

據說 Android 2.2 的虛擬機 dalvik 使用了 JIT 技術,使其運行速度快了5倍。

dalvik 解釋并執行程序,JIT 技術主要是對多次運行的代碼進行編譯,當再次調用時使用編譯之后的機器碼,而不是每次都解釋,以節約時間。5倍是測試程序測出的值,并不是說程序運行速度也能達到5倍,這是因為測試程序有很多的重復調用和循環,而一般程序主要是順序執行的,而且它是一邊運行,一邊編譯,一開始的時候提速不多,所以真正運行程序速度提高不是特別明顯。

每啟動一個應用程序,都會相應地啟動一個 dalvik 虛擬機,啟動時會建立JIT 線程,一直在后臺運行。當某段代碼被調用時,虛擬機會判斷它是否需要編譯成機器碼,如果需要,就做一個標記,JIT 線程不斷判斷此標記,如果發現被設定就把它編譯成機器碼,并將其機器碼地址及相關信息放入 entry table 中,下次執行到此就跳到機器碼段執行,而不再解釋執行,從而提高速度。

odex(optimized dex)

因為 apk 實際為 zip 壓縮包,虛擬機每次加載都需要從 apk 中讀取classes.dex 文件,這樣會耗費很多的時間,而如果采用了 odex 方式優化的 dex 文件,他包含了加載 dex 必須的依賴庫文件列表,只需要直接加載而不需要再去解析。

Android N 之前,對于在 dalvik 環境中 使用 dexopt 來對 dex 字節碼進行優化生成 odex 文件最終存在手機的 data/dalvik-cache 目錄下,最后把 apk 文件中的 dex 文件刪除。

Android O 之后,odex 是從 vdex 這個文件中 提取了部分模塊生成的一個新的可執行二進制碼文件 , odexvdex 中提取后,vdex 的大小就減少了。

  • 第一次開機就會生成在 /system/app/<packagename>/oat/
  • 在系統運行過程中,虛擬機將其 從 /system/appcopy/data/davilk-cache/ 下;
  • odex + vdex = apk 的全部源碼 (vdex 并不是獨立于 odex 的文件 odex + vdex 才代表一個 apk );

AOT(Ahead-of-time)

ART 推出了預先 (AOT) 編譯,可提高應用的性能。ART 還具有比 Dalvik 更嚴格的安裝時驗證。在安裝時,ART 使用設備自帶的 dex2oat 工具來編譯應用。該實用工具接受 DEX 文件作為輸入,并針對目標設備生成已編譯應用的可執行文件。之后打開 App 的時候,不需要額外的翻譯工作,直接使用本地機器碼運行,因此運行速度提高。

AOTart 的核心,oat 文件包含 oatdataoatexec。前者包含 dex 文件內容,后者包含生成的本地機器指令,從這里看出 oat 文件回會比 dex 文件占用更大的存儲空間。

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

push 一個新的 apk 文件覆蓋之前 /system/appapk 文件,會觸發 PKMS 掃描時下發 force_dex flag ,強行生成新的 vdex文件 ,覆蓋之前的vdex 文件,由于某種機制,這個新 vdex 文件會 copy/data/dalvik-cache/ 下,于是 art 文件也變化了。

混合運行時

Android N 開發者預覽版包含了一個混合模式的運行時。應用在安裝時不做編譯,而是解釋字節碼,所以可以快速啟動。ART中有一種新的、更快的解釋器,通過一種新的 JIT 完成,但是這種 JIT 的信息不是持久化的。取而代之的是,代碼在執行期間被分析,分析結果保存起來。然后,當設備空轉和充電的時候,ART 會執行針對“熱代碼”進行的基于分析的編譯,其他代碼不做編譯。為了得到更優的代碼,ART 采用了幾種技巧包括深度內聯。

對同一個應用可以編譯數次,或者找到變“熱”的代碼路徑或者對已經編譯的代碼進行新的優化,這取決于分析器在隨后的執行中的分析數據。這個步驟仍被簡稱為 AOT,可以理解為“全時段的編譯”(All-Of-the-Time compilation)。

這種混合使用 AOT、解釋、JIT 的策略的全部優點如下。

  • 即使是大應用,安裝時間也能縮短到幾秒;
  • 系統升級能更快地安裝,因為不再需要優化這一步;
  • 應用的內存占用更小,有些情況下可以降低 50%;
  • 改善了性能;
  • 更低的電池消耗;

vdex

官網回答:ART的運作方式
dex2oat 工具接受一個 APK 文件,并生成一個或多個編譯工件文件,然后運行時將會加載這些文件。文件的個數、擴展名和名稱會因版本而異。
在 Android O 版本中,將會生成以下文件:

  • .vdex:其中包含 APK 的未壓縮 DEX 代碼,另外還有一些旨在加快驗證速度的元數據。
  • .odex:其中包含 APK 中已經過 AOT 編譯的方法代碼。
  • .art (optional):其中包含 APK 中列出的某些字符串和類的 ART 內部表示,用于加快應用啟動速度。
  • 第一次開機就會生成在 /system/app/<packagename>/oat/ 下;
  • 在系統運行過程中,虛擬機將其 從 /system/appcopy/data/davilk-cache/ 下。

ELF文件

ELF(Executable and Linking Format)是一種對象文件的格式,用于定義不同類型的對象文件(Object files)中都放了什么東西、以及都以什么樣的格式去放這些東西。它自最早在 System V系統上出現后,被 xNIX 世界所廣泛接受,作為缺省的二進制文件格式來使用。可以說,ELF 是構成眾多 xNIX 系統的基礎之一。

apk安裝過程

大家都知道 apk 其實就是 zipapk 安裝過程其實就是解壓過程。
用戶應用安裝涉及以下幾個目錄:

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

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

dalvik-cache.jpeg

Android8.0 版本下 dex2oat 工具生成的三個.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

文中部分內容摘自:
深入理解JVM-字節碼執行引擎
知乎-Dalvik 虛擬機和 Sun JVM 在架構和執行方面有什么本質區別?
《Java虛擬機原理圖解》4.JVM機器指令集
Android[art]-Android dex,odex,oat,vdex,art文件結構學習總結
Android N 混合使用 AOT 編譯,解釋和 JIT 三種運行時

修改歷史:
【第一次發布】2017.09.18 19:00
【第二次主要修改不oat、vdex和odex相關內容】2020.04.02 22:00

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

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

推薦閱讀更多精彩內容