JVM和Dalvik/ART
Android應(yīng)用程序運(yùn)行在Dalvik/ART虛擬機(jī),并且每一個應(yīng)用程序?qū)?yīng)有一個單獨(dú)的Dalvik虛擬機(jī)實(shí)例棕诵。Dalvik虛擬機(jī)實(shí)則也算是一個Java虛擬機(jī)裁良,只不過它執(zhí)行的不是class文件,而是dex文件校套。Dalvik虛擬機(jī)與Java虛擬機(jī)共享有差不多的特性价脾,差別在于兩者執(zhí)行的指令集是不一樣的,前者的指令集是基本寄存器的笛匙,而后者的指令集是基于堆棧的侨把。
基于棧的虛擬機(jī)
對于基于棧的虛擬機(jī)來說,每一個運(yùn)行時的線程妹孙,都有一個獨(dú)立的棧秋柄。棧中記錄了方法調(diào)用的歷史,每有一次方法調(diào)用蠢正,棧中便會多一個棧楨骇笔。最頂部的棧楨稱作當(dāng)前棧楨,其代表著當(dāng)前執(zhí)行的方法嚣崭”看ィ基于棧的虛擬機(jī)通過操作數(shù)棧進(jìn)行所有操作。
public class Demo {
public static void test() {
int a = 1;
int b = 2;
int c = a + b;
}
}
使用javap -c xxx.class
進(jìn)行反編譯雹舀,查看字節(jié)碼指令:
- iconst_1:將int類型常量a壓入操作數(shù)棧
- istore_0:將int類型常量a存入局部變量0
- iadd:執(zhí)行int類型的加法操作
執(zhí)行過程如下:
基于寄存器的虛擬機(jī)
寄存器是CPU的組成部分芦劣。寄存器是有限存貯容量的高速存貯部件,它們可用來暫存指令说榆、數(shù)據(jù)和位址虚吟。
基于寄存器的虛擬機(jī)中沒有操作數(shù)棧系吩,但是有很多虛擬寄存器坚弱。其實(shí)和操作數(shù)棧相同,這些寄存器也存放在運(yùn)行時棧中灶似,本質(zhì)上就是一個數(shù)組荠卷。與JVM相似模庐,在Dalvik VM中每個線程都有自己的PC和調(diào)用棧,方法調(diào)用的活動記錄以幀為單位保存在調(diào)用棧上油宜。
與JVM版相比掂碱,可以發(fā)現(xiàn)Dalvik版程序的指令數(shù)明顯減少了,數(shù)據(jù)移動次數(shù)也明顯減少了慎冤。
ART和Dalvik
Dalvik虛擬機(jī)執(zhí)行的是dex字節(jié)碼疼燥,解釋執(zhí)行。 從Android 2.2版本開始蚁堤,支持JIT即時編譯(Just In Time)在程序運(yùn)行的過程中進(jìn)行選擇熱點(diǎn)代碼(經(jīng)常執(zhí)行的代碼)進(jìn)行編譯或者優(yōu)化醉者。而ART(Android Runtime) 是在 Android 4.4 中引入的一個開發(fā)者選項,也是 Android 5.0 及更高版本的默認(rèn) Android 運(yùn)行時。ART虛擬機(jī)執(zhí)行的是本地機(jī)器碼撬即。 Android的運(yùn)行時從Dalvik虛擬機(jī)替換成ART虛擬機(jī)立磁,并不要求開發(fā)者將自己的應(yīng)用直接編譯成目標(biāo)機(jī)器碼,APK仍然是一個包含dex字節(jié)碼的文件剥槐。
dex2aot
Dalvik下應(yīng)用在安裝的過程唱歧,會執(zhí)行一次優(yōu)化,將dex字節(jié)碼進(jìn)行優(yōu)化生成odex文件粒竖。而Art下將應(yīng)用的dex字節(jié)碼翻譯成本地機(jī)器碼的最恰當(dāng)AOT時機(jī)也就發(fā)生在應(yīng)用安裝的時候颅崩。ART 引入了預(yù)先編譯機(jī)制**(Ahead Of Time),在安裝時蕊苗,ART 使用設(shè)備自帶的 dex2oat 工具來編譯應(yīng)用沿后,dex中的字節(jié)碼將被編譯成本地機(jī)器碼。
Android N(7.0)的運(yùn)作方式
ART 使用預(yù)先 (AOT) 編譯朽砰,并且從 Android N混合使用AOT編譯得运,解釋和JIT。
1锅移、最初安裝應(yīng)用時不進(jìn)行任何 AOT 編譯(安裝又快了),運(yùn)行過程中解釋執(zhí)行饱搏,對經(jīng)常執(zhí)行的方法進(jìn)行JIT非剃,經(jīng)過 JIT 編譯的方法將會記錄到Profile配置文件中。
2推沸、當(dāng)設(shè)備閑置和充電時备绽,編譯守護(hù)進(jìn)程會運(yùn)行,根據(jù)Profile文件對常用代碼進(jìn)行 AOT 編譯鬓催。待下次運(yùn)行時直接使用肺素。
類加載機(jī)制
雙親委派機(jī)制
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//檢查類是否已經(jīng)被加載過
Class<?> c = findLoadedClass(name);
if (c == null) {
//沒被加載過,就去加載該類
try {
if (parent != null) {
//parent不為null宇驾,則調(diào)用parent的loadClass去加載
c = parent.loadClass(name, false);
} else {
//parent為null倍靡,則調(diào)用BootClassLoader去加載類(從Framework中找)
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
//如果還是找不到,就調(diào)用findClass自己去找(從app中找)
c = findClass(name);
}
}
return c;
}
某個類加載器在加載類時课舍,首先將加載任務(wù)委托給父類加載器塌西,依次遞歸,如果父類加載器可以完成類加載任務(wù)筝尾,就成功返回捡需;只有父類加載器無法完成此加載任務(wù)或者沒有父類加載器時,才自己去加載筹淫。
好處:
1站辉、避免重復(fù)加載,當(dāng)父加載器已經(jīng)加載了該類的時候,就沒有必要子ClassLoader再加載一次饰剥。
2殊霞、安全性考慮,防止核心API庫被隨意篡改捐川。
類加載過程
關(guān)注木水小站 (zhangmushui.cn)和微信公眾號【木水Code】脓鹃,及時獲取更多最新技術(shù)干貨。