Java&Android 基礎知識梳理(7) Android 虛擬機器

澤毛發表於2017-12-21

一、Dalvik 虛擬機器

DalvikGoogle公司自己設計用於Android平臺的Java虛擬機器,它是Android平臺的重要組成部分,支援dex格式的Java應用程式的執行。

Dalvik作為面向Linux、為嵌入式作業系統設計的虛擬機器,主要負責完成 物件生命週期管理、堆疊管理、執行緒管理、安全和異常管理,以及垃圾回收等。Dalvik充分利用Linux程式管理的特定,對其進行了物件導向的設計,使得可以 同時執行多個程式,而傳統的Java程式通常只能執行一個程式。

1.1 Dalvik 虛擬機器和 JVM 的對比

區別一

  • 大多數的JVM虛擬機器基於 棧的結構,基於棧的指令更緊湊,使用的指令只佔用一個位元組,因而成為位元組碼。
  • Dalvik虛擬機器則是基於 暫存器,基於暫存器的指令由於需要指定源地址和目標地址,因此需要佔用更多的指令空間,某些指令需要佔用兩個位元組。

區別二

  • Java虛擬機器執行的是Java位元組碼。Java類會被編譯成一個或者多個.class檔案,然後打包到jar檔案中,接著Java虛擬機器會從相應的.class檔案和.jar檔案中獲取對應的位元組碼。
  • Dalvik虛擬機器執行的是.dex檔案。在Java類被編譯成.class檔案後,還會通過dx工具將所有的.class檔案轉換一個.dex檔案,Dalvik虛擬機器再從中讀取指令和資料。.dex檔案除了減少整體的檔案尺寸和I/O操作次數,也提高了類的查詢速度。

區別三

  • class檔案中包含多個不同的方法簽名,如果A類檔案引用B類檔案中的方法,方法簽名也會被複制到A類檔案中(在虛擬機器載入類的連線階段將會使用該簽名連結到B類的對應方法),也就是說,多個不同的類會同時包含相同的方法簽名,同樣地,大量的字串常量在多個類檔案中也被重複使用,這些冗餘資訊會直接增加檔案的體積,而JVM在把描述類的資料從.class檔案載入到記憶體時,需要對資料進行校驗、轉換解析和初始化,最終才形成可以被虛擬機器直接使用的JAVA型別,因為大量的冗餘資訊,會嚴重影響虛擬機器解析檔案的效率。
  • .dex檔案中,由於dx工具會對JAVA類檔案重新排列,將所有JAVA類檔案中的常量池分解,消除其中的冗餘資訊,重新組合形成一個常量池,所有的類檔案共享同一個常量池,使得相同的字串、常量在.dex檔案中只出現一次,從而減小了檔案的體積。

1.2 Dalvik 虛擬機器特點

  • 使用dex格式的位元組碼,不相容Java位元組碼格式
  • 程式碼密度小,執行效率高,節省資源
  • 常量池只使用32位的索引
  • 有記憶體限制
  • 預設棧大小是12KB
  • 堆預設啟動大小為2MB,預設最大值為16MB
  • 堆支援的最小啟動大小為1MB,支援的最大值為1024MB
  • 堆和棧引數可以通過-Xms-Xmx修改

1.3 Dalvik 系統架構

1.3.1 dex 檔案結構

.class 檔案與 .dex 檔案對比

.dex檔案結構和.class檔案結構差異的地方很多,但從攜帶的資訊上看,.dex.class檔案是一致的:

  • header:儲存了各個資料型別的起始地址、偏移量等資訊。
  • proto_ids:描述函式原型資訊,包括返回值,引數資訊。比如“test:()V”
  • methods_ids:函式資訊,包括所屬類及對應的proto資訊。

雖然.dex檔案的結構很緊湊,但想要執行時的效能得到進一步提升,還需要對dex檔案進行進一步優化。優化主要針對以下幾個方面:

  • 調整所有欄位的位元組序和對齊結構中的每一個域
  • 驗證.dex檔案中的所有類
  • 對一些特定的類進行優化,對方法裡的操作碼進行優化

.dex檔案經過優化後檔案大小會膨脹,大約增加到原來的1~4倍。對於內建應用,一般在系統編譯後,便會生成優化檔案odex(Optimized dex)。一個Android應用程式,需要經過以下過程才可以在Dalvik虛擬機器上執行:

  • Java原始檔編譯成.class檔案
  • 使用dx工具把.class檔案轉換成.dex檔案
  • 使用aapt工具把.dex檔案、資原始檔以及AndroidManifest.xml檔案組合成APK
  • APK安裝到Android裝置執行

.apk 檔案的產生過程

1.3.2 Dalvik 類載入器

一個dex檔案需要類載入器載入原生類和Java類,然後通過直譯器根據指令集對Dalvik位元組碼進行解釋和執行。Dalvik類載入器使用mmap函式,將dex檔案對映到記憶體中,通過普通的記憶體讀取操作即可訪問dex檔案,然後解析dex檔案內容並載入其中的類到雜湊表中。

解析 dex

總的來說,dex檔案可以抽象為三個部分:頭部、索引、資料。通過頭部可以知道索引的位置和數目,以及資料區的起始位置。將dex檔案對映到記憶體後,Dalvik會呼叫dexFileParse函式對其進行分析,分析的結果放到DexFile資料結構中。DexFile中的baseAddr指向對映區的起始位置,pClassDefs指向class索引的起始位置。為了加快class的查詢速度,還建立一個雜湊表,對class名字進行雜湊並生成索引。

載入 class

解析工作完成後就進行class的載入,載入的類需要用ClassObject資料結構來儲存。

typedef struct Object {
    ClassObject* clazz;  // 型別物件
    Lock lock;           // 鎖物件
} Object;
複製程式碼

其中clazz指向ClassObject物件,還包含一個Lock物件。如果其它執行緒想要獲取它的鎖,只有等這個執行緒釋放。Dalvik每載入一個class都會對應一個ClassObject物件,載入過程會在記憶體中分配幾個區域,分別存放directMethodvirtualMethodsfieldifield。這些資訊從dex檔案的資料區中讀取。欄位Field的定義如下:

struct Field {
    ClassObject* clazz;    //所屬型別
    const char* name;      // 變數名稱
    const char* signature; // 如“Landroid/os/Debug;”
    u4 accessFlags;        // 訪問標記
    
    #ifdef PROFILE_FIELD_ACCESS
        u4 gets;
        u4 puts;
    #endif
};
複製程式碼

待得到class索引後,實際的載入由loadClassFromDex來完成。首先它會讀取class的具體資料,分別載入directMethodvirtualMethodifieldsfield,然後為ClassObject資料結構分配記憶體,並讀取dex檔案的相關資訊。載入完成後,將載入的class通過dvmAddClassToHash函式放入雜湊表,以方便下次查詢;最後,通過dvmLinkClass查詢該類的超類,如果有介面類則載入相應的介面類。

1.3.3 Dalvik 直譯器

對於任何虛擬機器來說,直譯器無疑是核心的部分,所有的Java位元組碼都經過直譯器解釋執行。由於Dalvik直譯器的效率很重要,Android分別實現了C語言版和各種組合語言版的直譯器。直譯器通常是迴圈執行,需要一個入口函式呼叫處理程式執行第一條指令,而後每條指令執行時引出下一條指令,通過函式指標呼叫處理程式。

二、Dalvik 虛擬機器和 ART 虛擬機器對比

Android 4.4之後,Google開始使用了更加優秀的ART虛擬機器來替換Dalvik虛擬機器,下面我們就來對比一下這兩者之間的區別。

2.1 Dalvik

打包的過程中 會先將.java等原始碼通過javac編譯成.class檔案,再通過dx.class檔案轉換成Dalvik虛擬機器執行的.dex檔案。

應用啟動的時候 先將.dex檔案 轉換成機器碼,又因為65536的檔案,導致在應用冷啟動的時候有一個合包的過程,最後的結果就是app的啟動時間有可能變慢,這就是Dalvik虛擬機器的JIT(Just in Time)特性。

2.2 ART

ART除了相容了Dalvik虛擬機器的特性之外,還有一個很好的特性AOT(Ahead of Time),這個特性就是把 .dex 檔案轉換成機器碼 這個步驟提前到了 應用安裝 的時候,ART虛擬機器將.dex檔案轉換成可直接執行的.oat檔案,ART虛擬機器天生支援多dex,所以也不會有一個合包的過程,因此會極大的提升APP冷啟動速度。

2.3 ART 虛擬機器的優缺點

優點:

  • 加快APP冷啟動速度
  • 提升GC速度
  • 提供功能全面的Debug特性

缺點:

  • APP安裝速度慢,因為在APK安裝的時候要生成可執行.oat檔案
  • APK佔用空間大,因為在APK安裝的時候要生成可執行.oat檔案

三、參考文獻

理解 Android 虛擬機器體系結構 Android Dalvik 虛擬機器和 ART 虛擬機器對比

Dalvik 虛擬機器簡要介紹和學習計劃 Dalvik 虛擬機器的啟動過程分析 Dalvik 虛擬機器的執行過程分析

深入理解 Dalvik 虛擬機器 - Android應用程式啟動過程分析 深入理解 ART 虛擬機器 - 虛擬機器的啟動 深入理解 ART 虛擬機器 - ART 的函式執行機制 深入理解 Dalvik 虛擬機器 - 直譯器的執行機制 深入理解ART虛擬機器 - ImageSpace的載入過程分析


更多文章,歡迎訪問我的 Android 知識梳理系列:

相關文章