個人博客地址 http://dandanlove.com/
現在市面上的 Android
手機大部分都是運行的是ART虛擬機了。還記得自己一部 Android
手機(HuaweiG520
),Android4.1
系統。那時候還是沒有 ART虛擬機
的。作爲Android
開發者,我們應該對 Android
的發展歷史有些瞭解爲什麼 Android
會經歷這麼多的變化。Android
是先有 JVM
然後是 Dalvik
,接着是現在的 ART虛擬機
。那麼他們之間有什麼關係呢?
Dalvik和ART
JVM就不用講述了大家都有了解,不瞭解的參見JVM百度百科。
Dalvik
是Android
平臺的虛擬機,是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總結
想要了解更多:基於棧的虛擬機 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
這個文件中 提取了部分模塊生成的一個新的可執行二進制碼文件 , odex
從 vdex
中提取後,vdex
的大小就減少了。
- 第一次開機就會生成在
/system/app/<packagename>/oat/
下 - 在系統運行過程中,虛擬機將其 從
/system/app
下copy
到/data/davilk-cache/
下; odex + vdex = apk
的全部源碼 (vdex
並不是獨立於odex
的文件odex + vdex
才代表一個apk
);
AOT(Ahead-of-time)
ART
推出了預先 (AOT
) 編譯,可提高應用的性能。ART
還具有比 Dalvik
更嚴格的安裝時驗證。在安裝時,ART
使用設備自帶的 dex2oat
工具來編譯應用。該實用工具接受 DEX 文件作爲輸入,並針對目標設備生成已編譯應用的可執行文件。之後打開 App
的時候,不需要額外的翻譯工作,直接使用本地機器碼運行,因此運行速度提高。
AOT
是 art
的核心,oat
文件包含 oatdata
和 oatexec
。前者包含 dex
文件內容,後者包含生成的本地機器指令,從這裏看出 oat
文件回會比 dex
文件佔用更大的存儲空間。
因爲 oat
文件包含生成的本地機器指令進而可以直接運行,它同樣保存在手機的 data/dalvik-cache
目錄下 PMS(PackgetManagerService)—>installd(守護進程)——>dex2oat(/system/bin/dex2oat)
。注意存放在 data/dalvik-cache
目錄下的後綴名都仍爲 .dex
前者其實表示一個優化過的 .dex
文件 後者爲 .art
文件。
push
一個新的 apk
文件覆蓋之前 /system/app
下 apk
文件,會觸發 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/app
下copy
到/data/davilk-cache/
下。
ELF文件
ELF(Executable and Linking Format
)是一種對象文件的格式,用於定義不同類型的對象文件(Object files
)中都放了什麼東西、以及都以什麼樣的格式去放這些東西。它自最早在 System V
系統上出現後,被 xNIX
世界所廣泛接受,作爲缺省的二進制文件格式來使用。可以說,ELF
是構成衆多 xNIX
系統的基礎之一。
apk安裝過程
大家都知道 apk
其實就是 zip
包 apk
安裝過程其實就是解壓過程。
用戶應用安裝涉及以下幾個目錄:
data/app
安裝目錄 安裝時會把apk
文件copy
到這裏;data/dalvik-cache
如上述描述中的存放.dex
(.odex
無論davilk
的dex
還是art
的oat
格式);data/data/pkg/
存放應用程序的數據;
Android5.1
版本下oat
文件都以.dex
文件在data/dalvik-cache
目錄下:
Android8.0
版本下dex2oat
工具生成的三個.art,.odex,.vdex
文件都在data/dalvik-cache
目錄下:
Android8.0
版本下搜狗輸入法在data/app/com.sohu.inputmethod.sogou.xiaomi-JAKuH_Jhlk6Y36zKoTUN8Q==
目錄下:
Android8.0
版本下搜狗輸入法在system/app/SogouInput
目錄下:
文中部分內容摘自:
深入理解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
文章到這裏就全部講述完啦,若有其他需要交流的可以留言哦!!
想閱讀作者的更多文章,可以查看我 個人博客 和公共號: