1. 程式人生 > >Android內存優化(一)DVM和ART原理初探

Android內存優化(一)DVM和ART原理初探

java虛擬機 劃分 cimage beef 靜態 由於 jar blank 查找

要學習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文件 技術分享

如上圖所示,.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架構如下圖所示。

技術分享 從上圖可以看出,首先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的運行時堆空間劃分如下圖所示。

技術分享

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

Android內存優化(一)DVM和ART原理初探