標籤:
首先,讓我們來思考下面幾個問題:
什麼是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共用一塊記憶體地區,大大節省了記憶體開銷。
轉 Android Dalvik虛擬機器初識