現(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百度百科叼风。
Dalvik
是Android
平臺(tái)的虛擬機(jī)取董,是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é)
想要了解更多:基于棧的虛擬機(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)制碼文件 灌旧, odex
從 vdex
中提取后,vdex
的大小就減少了绰筛。
- 第一次開機(jī)就會(huì)生成在
/system/app/<packagename>/oat/
下 - 在系統(tǒng)運(yùn)行過程中枢泰,虛擬機(jī)將其 從
/system/app
下copy
到/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)行速度提高一姿。
AOT
是 art
的核心七咧,oat
文件包含 oatdata
和 oatexec
。前者包含 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/app
下 apk
文件蜂林,會(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/app
下copy
到/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í)就是 zip
包 apk
安裝過程其實(shí)就是解壓過程搀缠。
用戶應(yīng)用安裝涉及以下幾個(gè)目錄:
-
data/app
安裝目錄 安裝時(shí)會(huì)把apk
文件copy
到這里; -
data/dalvik-cache
如上述描述中的存放.dex
(.odex
無論davilk
的dex
還是art
的oat
格式); -
data/data/pkg/
存放應(yīng)用程序的數(shù)據(jù);
Android5.1
版本下oat
文件都以.dex
文件在data/dalvik-cache
目錄下:
Android8.0
版本下dex2oat
工具生成的三個(gè).art铛楣,.odex,.vdex
文件都在data/dalvik-cache
目錄下:
Android8.0
版本下搜狗輸入法在data/app/com.sohu.inputmethod.sogou.xiaomi-JAKuH_Jhlk6Y36zKoTUN8Q==
目錄下:
Android8.0
版本下搜狗輸入法在system/app/SogouInput
目錄下:
文中部分內(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
文章到這里就全部講述完啦矢洲,若有其他需要交流的可以留言哦~!~缩焦!