Android記憶體優化(一)DVM和ART原理初探

劉望舒發表於2017-06-06

相關文章
Android效能優化系列
Java虛擬機器系列

前言

要學習Android的記憶體優化,首先要了解Java虛擬機器,此前我用了多篇文章來介紹Java虛擬機器的知識,就是為了這個系列做鋪墊。在Android開發中我們接觸的是與Java虛擬機器類似的Dalvik虛擬機器和ART虛擬機器,這一篇我們就來了解它們的基本原理。

1.Dalvik虛擬機器

Dalvik虛擬機器( Dalvik Virtual Machine ),簡稱Dalvik VM或者DVM。它是由Dan Bornstein編寫的,名字源於他的祖先居住過的名為Dalvik的小漁村。DVM是Google專門為Android平臺開發的虛擬機器,它執行在Android執行時庫中。需要注意的是DVM並不是一個Java虛擬機器(以下簡稱JVM),至於為什麼,下文會給你答案。

DVM與JVM的區別

DVM之所以不是一個JVM ,主要原因是DVM並沒有遵循JVM規範來實現。DVM與JVM主要有以下區別。

基於的架構不同
JVM基於棧則意味著需要去棧中讀寫資料,所需的指令會更多,這樣會導致速度慢,對於效能有限的移動裝置,顯然不是很適合。
DVM是基於暫存器的,它沒有基於棧的虛擬機器在拷貝資料而使用的大量的出入棧指令,同時指令更緊湊更簡潔。但是由於顯示指定了運算元,所以基於暫存器的指令會比基於棧的指令要大,但是由於指令數量的減少,總的程式碼數不會增加多少。

執行的位元組碼不同
在Java SE程式中,Java類會被編譯成一個或多個.class檔案,打包成jar檔案,而後JVM會通過相應的.class檔案和jar檔案獲取相應的位元組碼。執行順序為: .java檔案 -> .class檔案 -> .jar檔案
而DVM會用dx工具將所有的.class檔案轉換為一個.dex檔案,然後DVM會從該.dex檔案讀取指令和資料。執行順序為:
.java檔案 –>.class檔案-> .dex檔案

Android記憶體優化(一)DVM和ART原理初探

如上圖所示,.jar檔案裡面包含多個.class檔案,每個.class檔案裡面包含了該類的常量池、類資訊、屬性等等。當JVM載入該.jar檔案的時候,會載入裡面的所有的.class檔案,JVM的這種載入方式很慢,對於記憶體有限的移動裝置並不合適。
而在.apk檔案中只包含了一個.dex檔案,這個.dex檔案裡面將所有的.class裡面所包含的資訊全部整合在一起了,這樣再載入就提高了速度。.class檔案存在很多的冗餘資訊,dex工具會去除冗餘資訊,並把所有的.class檔案整合到.dex檔案中,減少了I/O操作,提高了類的查詢速度。

DVM允許在有限的記憶體中同時執行多個程式
DVM經過優化,允許在有限的記憶體中同時執行多個程式。在Android中的每一個應用都執行在一個DVM例項中,每一個DVM例項都執行在一個獨立的程式空間。獨立的程式可以防止在虛擬機器崩潰的時候所有程式都被關閉。

DVM由Zygote建立和初始化
Android系統啟動流程(二)解析Zygote程式啟動過程這篇文章中我介紹過 Zygote,可以稱它為孵化器,它是一個DVM程式,同時它也用來建立和初始化DVM例項。每當系統需要建立一個應用程式時,Zygote就會fock自身,快速的建立和初始化一個DVM例項,用於應用程式的執行。

DVM架構

DVM的原始碼位於dalvik/目錄下,其中dalvik/vm目錄下的內容是DVM的具體實現部分,它會被編譯成libdvm.so;dalvik/libdex會被編譯成libdex.a靜態庫,作為dex工具使用;dalvik/dexdump是.dex檔案的反編譯工具;DVM的可執行程式位於dalvik/dalvikvm中,將會被編譯成dalvikvm可執行程式。DVM架構如下圖所示。

Android記憶體優化(一)DVM和ART原理初探

從上圖可以看出,首先Java編譯器編譯的.class檔案經過DX工具轉換為.dex檔案,.dex檔案由類載入器處理,接著直譯器根據指令集對Dalvik位元組碼進行解釋、執行,最後交與Linux處理。

DVM的執行時堆

DVM的執行時堆主要由兩個Space以及多個輔助資料結構組成,兩個Space分別是Zygote Space(Zygote Heap)和Allocation Space(Active Heap)。Zygote Space用來管理Zygote程式在啟動過程中預載入和建立的各種物件,Zygote Space中不會觸發GC,所有程式都共享該區域,比如系統資源。Allocation Space是在Zygote程式fork第一個子程式之前建立的,它是一種私有程式,Zygote程式和fock的子程式在Allocation Space上進行物件分配和釋放。
除了這兩個Space,還包含以下資料結構:

  • Card Table:用於DVM Concurrent GC,當第一次進行垃圾標記後,記錄垃圾資訊。
  • Heap Bitmap:有兩個Heap Bitmap,一個用來記錄上次GC存活的物件,另一個用來記錄這次GC存活的物件。
  • Mark Stack:DVM的執行時堆使用標記-清除(Mark-Sweep)演算法進行GC,不瞭解標記-清除演算法的同學檢視Java虛擬機器(四)垃圾收集演算法這篇文章。Mark Stack就是在GC的標記階段使用的,它用來遍歷存活的物件。

2.ART虛擬機器

ART(Android Runtime)是Android 4.4釋出的,用來替換Dalvik虛擬,Android 4.4預設採用的還是DVM,系統會提供一個選項來開啟ART。在Android 5.0時,預設採用ART,DVM從此退出歷史舞臺。

ART與DVM的區別

DVM中的應用每次執行時,位元組碼都需要通過即時編譯器(JIT,just in time)轉換為機器碼,這會使得應用的執行效率降低。而在ART中,系統在安裝應用時會進行一次預編譯(AOT,ahead of time),將位元組碼預先編譯成機器碼並儲存在本地,這樣應用每次執行時就不需要執行編譯了,執行效率也大大提升。

ART的執行時堆

與DVM的GC不同的是,ART的GC型別有多種,主要分為Mark-Sweep GC和Compacting GC。ART的執行時堆的空間根據不同的GC型別也有著不同的劃分,如果採用的是Mark-Sweep GC,執行時堆主要是由四個Space和多個輔助資料結構組成,四個Space分別是Zygote Space、Allocation Space、Image Space和Large Object Space。Zygote Space、Allocation Space和DVM中的作用是一樣的。Image Space用來存放一些預載入類,Large Object Space用來分配一些大物件(預設大小為12k)。其中Zygote Space和Image Space是程式間共享的。
採用Mark-Sweep GC的執行時堆空間劃分如下圖所示。

Android記憶體優化(一)DVM和ART原理初探

除了這四個Space,ART的Java堆中還包括兩個Mod Union Table,一個Card Table,兩個Heap Bitmap,兩個Object Map,以及三個Object Stack。如果想要跟多的瞭解它們,請參考ART執行時Java堆建立過程分析 -- 羅昇陽這篇文章。

參考資料
《深入解析Android虛擬機器》
《Android技術內幕-系統卷》
《Android效能優化最佳實踐》
stackoverflow:關於dvm儲存的問題
Dalvik Virtual Machine -- COSC 530
ART執行時Java堆建立過程分析 -- 羅昇陽
Dalvik虛擬機器Java堆建立過程分析 -- 羅昇陽
ART執行時垃圾收集機制簡要介紹和學習計劃 -- 羅昇陽
Android 效能優化—Android memory 引數tuning(二)


歡迎關注我的微信公眾號,第一時間獲得部落格更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。

Android記憶體優化(一)DVM和ART原理初探

相關文章