Android Dalvik虛擬機初識



首先,讓我們來思考下面幾個問題:

什麼是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共享一塊內存區域,大大節省了內存開銷。

 

出處:

http://blog.csdn.net/andyxm/article/details/6126907/

首先,讓我們來思考下面幾個問題:

什麼是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共享一塊內存區域,大大節省了內存開銷。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章