現在市面上的 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
文章到這里就全部講述完啦,若有其他需要交流的可以留言哦~!~!