首先,讓我們來思考下面幾個問題:
什麼是Dalvik虛拟機?
Dalvik VM與JVM有什麼差別?
Dalvik VM有什麼新的特點?
Dalvik VM的架構是怎麼樣的?
首先,我得承認第一個問題問得很傻:什麼是Dalvik虛拟機?沒有人給出過一個明确的定義,但是,我們似乎可以從人們對Java虛拟機的描述中得到些資訊。
Java虛拟機(JVM)是一個虛構出來的計算機,是通過在實際的計算機上仿真模拟各種計算機功能來實作的。它有自己完善的硬體架構(如處理器、堆棧、寄存器等),還具有相應的指令系統。使用“Java虛拟機”程式就是為了支援與作業系統無關、在任何系統中都可以運作的程式。
是以,我們不妨對Dalvik虛拟機作出這樣的描述:
Dalvik虛拟機是Android程式的虛拟機,是Android中Java程式的運作基礎。其指令集基于寄存器架構,執行其特有的檔案格式——dex位元組碼來完成對象生命周期管理、堆棧管理、線程管理、安全異常管理、垃圾回收等重要功能。它的核心内容是實作庫(libdvm.so),大體由C語言實作。依賴于Linux核心的一部分功能——線程機制、記憶體管理機制,能高效使用記憶體,并在低速CPU上表現出的高性能。每一個Android應用在底層都會對應一個獨立的Dalvik虛拟機執行個體,其代碼在虛拟機的解釋下得以執行。
與Dalvik虛拟機關系最密切的非JVM莫屬,在Android源碼readme文檔中有這樣一段話:Much of the code under this directory originally came from the Apache Harmony project, and as such contains the standard Apache header comment. Some of the code was written originally for the Android project…
Dalvik VM與Apache Harmony 項目關系源遠流長,是以,與JVM關系自然就密切了。
然而:Dalvik VM ≠Java VM
dalvik基于寄存器,而JVM基于stack
Dalvik執行的是特有的DEX檔案格式,而JVM運作的是*.class檔案格式。
優勢:1、在編譯時提前優化代碼而不是等到運作時
2、 虛拟機很小,使用的空間也小;被設計來滿足可高效運作多種虛拟機執行個體。
3、常量池已被修改為隻使用32位的索引,以
簡化解釋器
JVM的位元組碼主要是零位址形式的,概念上說JVM是基于棧的架構。Google Android平台上的應用程式的主要開發語言是Java,通過其中的Dalvik VM來運作Java程式。為了能正确實作語義,Dalvik VM的許多設計都考慮到與JVM的相容性;但它卻采用了基于寄存器的架構,其位元組碼主要是二位址/三位址的混合形式。
基于棧與基于寄存器的架構,誰更快?現在實際的處理器,大多都是基于寄存器的架構,從側面反映出基于寄存器比基于棧的架構更與實際的處理器接近。但對于VM來說,源架構的求值棧或者寄存器都可能是用實際機器的記憶體來模拟的,是以性能特性與實際硬體又有不同。一般認為基于寄存器架構的Dalvik VM比基于棧架構JVM執行效率更高,原因是:雖然零位址指令更緊湊,但完成操作需要更多的load/store指令,也意味着更多的指令分派(instruction dispatch)次數與記憶體通路次數;通路記憶體是執行速度的一個重要瓶頸,二位址或三位址指令雖然每條指令占的空間較多,但總體來說可以用更少的指令完成操作,指令分派與記憶體通路次數都較少。
我們從下面的截圖可以明了的看到與同一段Java代碼對應的Java bytecode 與Dalvid bytecode的比較。
專有的DEX檔案格式
一個應用中會定義很多類,
編譯完成後即會有很多相應
的CLASS檔案,CLASS檔案
間會有不少備援的資訊。
dex位元組碼和标準Java的位元組碼(Class)在結構上的一個差別是dex位元組碼将多個檔案整合成一個,這樣,除了減少整體的檔案尺寸,I/O操作,也提高了類的查找速度。
原來每個類檔案中的常量池現在由DEX檔案中一個常量池來管理。
DEX檔案可以進行進一步優化。優化主要是針對以下幾個方面:
1、調整所有字段的位元組序(LITTLE_ENDIAN)和對齊結構中的沒一個域
2、驗證DEX檔案中的所有類
3、對一些特定的類進行優化,對方法裡的操作碼進行優化
優化 優化後的檔案大小會有所增加,應該是原DEX檔案的1-4倍。
odex是為了在運作過程中進一步提高性能,對dex檔案的進一步優化
一個應用,一個虛拟機執行個體,一個程序!!!
每一個Android應用都運作在一個Dalvik虛拟機執行個體裡,而每一個虛拟機執行個體都是一個獨立的程序空間。每個程序之間可以通信(IPC,Binder機制實作)。虛拟機的線程機制,記憶體配置設定和管理,Mutex等等都是依賴底層作業系統而實作的。
不同的應用在不同的程序空間裡運作,當一個虛拟機關閉或意外中止時不會對其它 虛拟機造成影響,可以最大程度的保護應用的安全和獨立運作。
Zygote是虛拟機執行個體的孵化器。AndroidRuntime.cpp中ZygoteInit.main()的執行會完成一個分裂,分裂出來的子程序繼續初始化Java層的架構,這個分裂出來的程序就是system_server。每當系統要求執行一個Android應用程式,Zygote就會FORK出一個子程序來執行該應用程式。這樣做的好處顯而易見:Zygote程序是在系統啟動時産生的,它會完成虛拟機的初始化,庫的加載,預置類庫的加載和初始化等等操作,而在系統需要一個新的虛拟機執行個體時,Zygote通過複制自身,最快速的提供個系統。另外,對于一些隻讀的系統庫,所有虛拟機執行個體都和Zygote共享一塊記憶體區域,大大節省了記憶體開銷。