Dalvik,ART與ODEX相愛相生
如果你有這樣的問題:
1.Dalvik和ART的區別
2.DEX在Dalvik轉化為ODEX和ART中轉化為ODEX的過程有上面區別
3.multidex在dalvik上起作用,ART上使用的也是multidex麼(如果不是的話在application中寫入multidex.install會對apk啟動造成影響麼)
如果你比較“懶”,,懶得看老羅的原始碼分析,,,長篇大論
請“簡要”看完以下“簡要”內容
一:Dalvik和ART的區別#
Dalvik: Dalvik是Google公司自己設計用於Android平臺的Java虛擬機器它可以支援已轉換為 .dex(即Dalvik Executable)格式的Java應用程式的執行,.dex格式是專為Dalvik設計的一種壓縮格式,適合記憶體和處理器速度有限的系統。執行的是位元組碼,它是依靠Just-In-Time (JIT)機制去解釋位元組碼
ART:即Android Runtime,google為了替代Dalvik專門為Android研發的。Android KK為開發者推出,L版本正式上線。比替代品更高效省電,執行的是本地機器碼(也就是linux的ELF檔案格式),依靠Ahead-Of-Time (AOT)機制
二.在不同平臺DEX轉化為ODEX的過程#
簡化流程如下:
這裡參考的是
http://blog.csdn.net/luoshengyang/article/details/18006645
android安裝過程原始碼分析:http://blog.csdn.net/luoshengyang/article/details/6747696
簡單來說,就是Android系統通過PackageManagerService來安裝APK,在安裝的過程,PackageManagerService會通過另外一個類Installer的成員函式dexopt來對APK裡面的dex位元組碼進行優化:
public final class Installer {
......
public int dexopt(String apkPath, int uid, boolean isPublic) {
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
builder.append(' ');
builder.append(uid);
builder.append(isPublic ? " 1" : " 0");
return execute(builder.toString());
}
......
}
這個函式定義在檔案frameworks/base/services/java/com/android/server/pm/Installer.java中。Installer通過socket向守護程式installd傳送一個dexopt請求,這個請求是由installd裡面的函式dexopt來處理的。詳細過程請移步Android ART執行時無縫替換Dalvik虛擬機器的過程分析
int dexopt(const char *apk_path, uid_t uid, int is_public)
{
struct utimbuf ut;
struct stat apk_stat, dex_stat;
char out_path[PKG_PATH_MAX];
char dexopt_flags[PROPERTY_VALUE_MAX];
char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
char *end;
int res, zip_fd=-1, out_fd=-1;
......
/* The command to run depend ones the value of persist.sys.dalvik.vm.lib */
property_get("persist.sys.dalvik.vm.lib", persist_sys_dalvik_vm_lib, "libdvm.so");
/* Before anything else: is there a .odex file? If so, we have
* precompiled the apk and there is nothing to do here.
*/
sprintf(out_path, "%s%s", apk_path, ".odex");
if (stat(out_path, &dex_stat) == 0) {
return 0;
}
if (create_cache_path(out_path, apk_path)) {
return -1;
}
......
out_fd = open(out_path, O_RDWR | O_CREAT | O_EXCL, 0644);
......
pid_t pid;
pid = fork();
if (pid == 0) {
......
if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
} else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
} else {
exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */
}
exit(68); /* only get here on exec failure */
}
......
}
……
static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
const char* output_file_name, const char* dexopt_flags)
{
static const char* DEX_OPT_BIN = "/system/bin/dexopt";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
char zip_num[MAX_INT_LEN];
char odex_num[MAX_INT_LEN];
sprintf(zip_num, "%d", zip_fd);
sprintf(odex_num, "%d", odex_fd);
ALOGV("Running %s in=%s out=%s\n", DEX_OPT_BIN, input_file_name, output_file_name);
execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
dexopt_flags, (char*) NULL);
ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
}
static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
const char* output_file_name, const char* dexopt_flags)
{
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
char oat_location_arg[strlen("--oat-name=") + PKG_PATH_MAX];
sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
execl(DEX2OAT_BIN, DEX2OAT_BIN,
zip_fd_arg, zip_location_arg,
oat_fd_arg, oat_location_arg,
(char*) NULL);
ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
}
函式定義在frameworks/native/cmds/installd/commands.c中 函式dexopt首先是讀取系統屬性persist.sys.dalvik.vm.lib的值,接著在/data/dalvik-cache目錄中建立一個odex檔案。這個odex檔案就是作為dex檔案優化後的輸出檔案。再接下來,函式dexopt通過fork來建立一個子程式。如果系統屬性persist.sys.dalvik.vm.lib的值等於libdvm.so,那麼該子程式就會呼叫函式run_dexopt來將dex檔案優化成odex檔案。另一方面,如果系統屬性persist.sys.dalvik.vm.lib的值等於libart.so,那麼該子程式就會呼叫函式run_dex2oat來將dex檔案翻譯成oat檔案,實際上就是將dex位元組碼翻譯成本地機器碼,並且儲存在一個oat檔案中。
函式run_dexopt通過呼叫/system/bin/dexopt來對dex位元組碼進行優化,而函式run_dex2oat通過呼叫/system/bin/dex2oat來將dex位元組碼翻譯成本地機器碼。注意,無論是對dex位元組碼進行優化,還是將dex位元組碼翻譯成本地機器碼,最終得到的結果都是儲存在相同名稱的一個odex檔案裡面的,但是前者對應的是一個dey檔案(表示這是一個優化過的dex),後者對應的是一個oat檔案(實際上是一個自定義的elf檔案,裡面包含的都是本地機器指令)。通過這種方式,原來任何通過絕對路徑引用了該odex檔案的程式碼就都不需要修改了。
三.oat檔案格式#
藉助羅大神的圖我們可以知道,OAT檔案本質上是一個ELF檔案,因此在最外層它具有一般ELF檔案的結構,例如它有標準的ELF檔案頭以及通過段(Section)來描述檔案內容。
OAT檔案包含有兩個特殊的段oatdata和oatexec,前者包含有用來生成本地機器指令的dex檔案內容,後者包含有生成的本地機器指令,它們之間的關係通過儲存在oatdata段前面的oat頭部描述。
APK安裝過程中生成的OAT檔案的輸入只有一個DEX檔案,也就是來自於打包在要安裝的APK檔案裡面的classes.dex檔案。實際上,一個OAT檔案是可以由若干個DEX生成的。這意味著在生成的OAT檔案的oatdata段中,包含有多個DEX檔案。詳細分析請移步Android執行時ART載入OAT檔案的過程分析
四.multidex載入odex,multidex和oat的關係
MultiDex在dalvik虛擬機器上的簡要安裝過程:
將/data/app/apkName.apk路徑下解壓得到的classes2.dex, …, classesN.dex,依次寫入到/data/data/pkgName/code_cache/secondary-dexes/apkName.apk.classes2.zip等zip檔案的classes.dex中,並返回這個zip列表。然後針對這個zip列表執行安裝過程,具體過程是,將這個要安裝的zip列表加入BaseDexClassLoader的pathList例項的dexElements陣列中,其中會針對各dex檔案進行dex2opt優化。一旦加入到了dexElements陣列中,程式啟動的時候,ClassLoader會載入dexElements陣列中的元素,從而實現multi dex的安裝。
上面提到OAT檔案可以由若干個dex生成,也就是不需要multidex去進行安裝,但是multidex是application中
進行Install的,跟虛擬機器關係不大。
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
在install函式中在執行從提取dex檔案列表前會做一些校驗操作,其中包含檢查APK是否已安裝,若APK已安裝,則不進行後續操作。檢查SDK版本號,版本號大於20不能保證MultiDex可正常Work
Set var2 = installedApk;
synchronized(installedApk) {
String apkPath = e.sourceDir;
if(installedApk.contains(apkPath)) {
return;
}
所以multidex在ART上不會影響程式的邏輯,它和ART沒有關係~。。。。
multidex原始碼分析:MultiDex安裝過程原始碼分析
小結:
從安裝過程上來看
Java的程式碼實際上需要兩次“轉換”才可以在android裝置上執行
一.PC端:.class->.dex->.apk
二.phone:dex->odex
區別在於第二步。
ART : .dex->.odex(機器碼)(AOT Ahead-Of-Time)
Dalvik: .dex->.odex(位元組碼)(JIT Just-In-Time)
機器碼可直接執行,而位元組碼每次啟動都需要執行將優化過的odex位元組碼再轉換成機器碼
ART優缺####
系統效能大幅提升
App啟動、執行更快
減少每次啟動的編譯增加電池續航
儲存佔用更大
安裝時間更長
ART、JIT、AOT、Dalvik之間有什麼關係?
JIT與Dalvik
JIT是"Just In Time Compiler"的縮寫,就是"即時編譯技術",與Dalvik虛擬機器相關。
怎麼理解這句話呢?這要從Android的一些特性說起。
JIT是在2.2版本提出的,目的是為了提高Android的執行速度,一直存活到4.4版本,因為在4.4之後的ROM中,就不存在Dalvik虛擬機器了。
我們使用Java開發android,在編譯打包APK檔案時,會經過以下流程
- Java編譯器將應用中所有Java檔案編譯為class檔案
- dx工具將應用編譯輸出的類檔案轉換為Dalvik位元組碼,即dex檔案
之後經過簽名、對齊等操作變為APK檔案。
Dalvik虛擬機器可以看做是一個Java VM,他負責解釋dex檔案為機器碼,如果我們不做處理的話,每次執行程式碼,都需要Dalvik將dex程式碼翻譯為微處理器指令,然後交給系統處理,這樣效率不高。
為了解決這個問題,Google在2.2版本新增了JIT編譯器,當App執行時,每當遇到一個新類,JIT編譯器就會對這個類進行編譯,經過編譯後的程式碼,會被優化成相當精簡的原生型指令碼(即native code),這樣在下次執行到相同邏輯的時候,速度就會更快。
當然使用JIT也不一定加快執行速度,如果大部分程式碼的執行次數很少,那麼編譯花費的時間不一定少於執行dex的時間。Google當然也知道這一點,所以JIT不對所有dex程式碼進行編譯,而是隻編譯執行次數較多的dex為本地機器碼。
有一點需要注意,那就是dex位元組碼翻譯成本地機器碼是發生在應用程式的執行過程中的,並且應用程式每一次重新執行的時候,都要做重做這個翻譯工作,所以這個工作並不是一勞永逸,每次重新開啟App,都需要JIT編譯。
另外,Dalvik虛擬機器從Android一出生一直活到4.4版本,而JIT在Android剛釋出的時候並不存在,在2.2之後才被新增到Dalvik中。
ART與AOT
AOT是"Ahead Of Time"的縮寫,指的就是ART(Anroid RunTime)這種執行方式。
前面介紹過,JIT是執行時編譯,這樣可以對執行次數頻繁的dex程式碼進行編譯和優化,減少以後使用時的翻譯時間,雖然可以加快Dalvik執行速度,但是還是有弊病,那就是將dex翻譯為本地機器碼也要佔用時間,所以Google在4.4之後推出了ART,用來替換Dalvik。
在4.4版本上,兩種執行時環境共存,可以相互切換,但是在5.0+,Dalvik虛擬機器則被徹底的丟棄,全部採用ART。
ART的策略與Dalvik不同,在ART 環境中,應用在第一次安裝的時候,位元組碼就會預先編譯成機器碼,使其成為真正的本地應用。之後開啟App的時候,不需要額外的翻譯工作,直接使用本地機器碼執行,因此執行速度提高。
當然ART與Dalvik相比,還是有缺點的。
- ART需要應用程式在安裝時,就把程式程式碼轉換成機器語言,所以這會消耗掉更多的儲存空間,但消耗掉空間的增幅通常不會超過應用程式碼包大小的20%
- 由於有了一個轉碼的過程,所以應用安裝時間難免會延長
但是這些與更流暢的Android體驗相比而言,不值一提。
總結
通過前面背景知識的介紹,我終於可以更簡單的介紹這四個名詞之間的關係了:
- JIT代表執行時編譯策略,也可以理解成一種執行時編譯器,是為了加快Dalvik虛擬機器解釋dex速度提出的一種技術方案,來快取頻繁使用的本地機器碼
- ART和Dalvik都算是一種Android執行時環境,或者叫做虛擬機器,用來解釋dex型別檔案。但是ART是安裝時解釋,Dalvik是執行時解釋
- AOT可以理解為一種編譯策略,即執行前編譯,ART虛擬機器的主要特徵就是AOT
複製貼上+理解,,,希望以後忘了能回來看看~!~
作者:SYfarming
連結:https://www.jianshu.com/p/389911e2cdfb
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
相關文章
- Dalvik虛擬機器、Java虛擬機器與ART虛擬機器虛擬機Java
- JAVA VM 與DalvikJava
- 我與快取的相愛相殺快取
- Solon詳解(11)- Mybatis 與 Solon 相親相愛MyBatis
- Dalvik 和 ART 有什麼區別?深扒 Android 虛擬機器發展史,真相卻出乎意料!Android虛擬機
- 5G與WiFi6相愛相殺的關係WiFi
- cookie和XSS, CSRF的相親相愛Cookie
- 愛相隨,想說愛你不容易
- GoPath模式和GoMoudle模式的相愛相殺Go模式
- 直播軟體app開發與相愛相殺的短影片如何共同穩住局面APP
- 軟體教練說:效能優化與效能設計,“相親相愛”的一對優化
- 相愛相殺:程式設計師的數學程式設計師
- 是成就還是削弱?AI程式碼生成工具與程式設計師的「相愛相殺」AI程式設計師
- Conversion to Dalvik format failed: Unable to execute dexORMAI
- Android上的Dalvik虛擬機器Android虛擬機
- DataStory:中產階級“焦慮感與幸福感”相愛相殺的8大特徵(附下載)AST特徵
- “LovePlus”系列:10年沉浮,愛難相隨
- 間市相生程己體例斷那usu
- Dalvik 和 Java 位元組碼的比較Java
- Android 的 ART 有何作用Android
- JINGWHALE ART 年度流行色
- 塔說|區塊鏈遇到資料庫:相愛還是相殺?區塊鏈資料庫
- The art of multipropcessor programming 讀書筆記-3. 自旋鎖與爭用(2)筆記
- 愛情,婚姻,與AIAI
- 「看圖」誰想幹掉誰?程式語言相愛相殺何時休
- java虛擬機器和Dalvik虛擬機器Java虛擬機
- Dalvik下一代殼通用解決方案
- 相愛相殺的雲端計算、大資料和人工智慧三兄弟大資料人工智慧
- Android上的ART虛擬機器Android虛擬機
- 也來看看Android的ART執行時Android
- ajax配合art-template模板引擎的使用
- AI界的State of the Art都在這裡了AI
- 知識總結二--個人愛好(非工作相關)
- 《蛋仔派對》某幻君&中國boy上演“相愛相殺”,過程爆笑無比
- 直播原始碼和短視訊原始碼,相親相愛的一家人原始碼
- 與“真愛粉”們談世嘉
- 智慧相機與工業相機的區別
- CSC1003 A2 T3 Ascii ArtASCII