萬盛學電腦網

 萬盛學電腦網 >> 手機應用 >> 安卓教程 >> 詳解 Android 虛擬機 ART 運行時庫 分析

詳解 Android 虛擬機 ART 運行時庫 分析

   ART 將會取代Dalvik虛擬機,因為 在Dalvik下,應用每次運行的時候,字節碼都需要通過即時編譯器轉換為機器碼,這會拖慢應用的運行效率,而在ART 環境中,應用在第一次安裝的時候,字節碼就會預先編譯成機器碼,使其成為真正的本地應用。

  在最新的Google I/O大會上,Google 發布了關於Android上最新的運行時庫的情況。這就是Android RunTime (ART). ART 將會取代Dalvik虛擬機,成為Android平台上Java代碼的執行工具。雖然自從Android KitKat,就有了一些關於ART的消息,但是基本都是一些新聞性質的,缺乏具體技術細節方面的介紹。本文嘗試綜合目前已有的各種消息,以及最新放出的 Android L 預覽版本的ROM的情況,對ART運行時庫做個詳細的分析。

詳解 Android 虛擬機 ART 運行時庫 分析   三聯

  和IOS,Windows,Tizen之類的移動平台直接將軟件編譯成能夠直接運行在特定硬件平台上的本地代碼不同。Android平台上的軟件會被編譯器首先編譯成通用的“byte-code”,然後再在具體的移動設備上被轉換成本地指令執行。

  從Android誕生至今的十幾年時間裡,Dalvik從開始時非常簡單的Java Byte-Code執行虛擬機,逐漸增加各種新的特性,滿足應用程序對性能的需求,以及與硬件設備協同演進。這其中包括在Android 2.2版本中引入的即時編譯器(JIT-Compiler), 以及隨後的多線程支持,以及其他一些優化。

Android平台的演進

  不過,在近兩年裡,Android整個生態系統的進步對Android虛擬機的需求,目前的Dalvik虛擬機的開發已經無法滿足了。Dalvik 最初設計時,處理器的性能很弱,移動設備的內存空間非常有限,而且都是32位的系統。於是Google開始構建一個新的虛擬機來更好的面對未來的發展趨勢。這種虛擬機的性能能夠在目前的多核處理器,甚至未來的8核處理上輕松擴展,能夠滿足對大容量存儲的支持,以及大容量內存的支持。 於是乎,ART出現了。

  1 架構介紹

APK文件的工作流

  首先,ART的首要設計需求就是完全兼容能在Dalvik上運行的byte-code,即dex(Dalvik executable)。這樣的話,對於程序員來說,就不需要對重新編譯已有的程序,直接拿APK就可以在Dalvik和ART虛擬機上運行。ART帶來的最大的變化,就是使用預編譯技術(Ahead-of-Time compile)取代Dalvik中的即時編譯技術(Just-In-Time compile)。之前,在應用程序每次執行的時候,虛擬機需要將bytecode編譯成本地碼執行,而在ART中這種編譯操作只需執行一次,隨後對該應用程序的執行都可以通過直接執行保存下來的本地碼完成。當然,這種預編譯技術,需要占用額外的存儲空間來存儲本地碼。正是因為現在移動設備的存儲空間越來越大,這種技術才得以應用。

  這種預編譯技術使得很多原來無法執行的編譯優化技術在新的Android平台上成為可能。因為代碼只被編譯和優化一次,因此值得花費更多的時間在這次編譯上,以便進行更多的優化。Google表示,現在可以在應用程序的整體代碼技術上進行更高層次的優化,因為編譯器現在能夠看到應用程序的整體代碼,而之前的即時編譯,編譯器只能看到並優化應用程序中某個函數或者非常小的一部分代碼。采用ART後,代碼中異常檢查帶來的開銷絕大部分可以避免,對方法和接口的調用也加快了很多。完成這部分功能的是新添加的“dex2oat”組件,用來替代Dalvik中對應的“dexopt”組件。Dalvik中的 Odex文件(優化後的dex)文件,在ART中也用ELF文件代替了。

  因為ART目前編譯生成ELF可執行文件,內核就可以直接對載入內存中的代碼進行分頁管理,這也會帶來更加高效的內存管理,以及更少的內存占用。說到這裡,我非常好奇內核中的KSM(Kernel same-page merging)在ART中會有什麼樣的影響,應該能帶來不錯的效果吧。我們拭目以待。

  ART對續航時間的影響也是非常顯著的。因為不再需要解釋執行,JIT也不用在程序運行時工作,這樣會直接節省CPU需要執行的指令數,因而耗電降低。

  因為預編譯時引入了更多分析和優化,編譯的時間會變長,這是ART可能會帶來的一個副作用。因此相比Dalvik虛擬機,當設備首次啟動及應用程序第一次安裝時,需要花費的時間更久。Google聲稱,這種時間上的增加並不那麼恐怖。他們希望並預期日後ART上完成上述動作的時間會和目前的 Dalvik差不多,甚至更短些。

ART與Dalvik性能比較

  上面的圖顯示,ART帶來的性能提升是非常明顯的。對於同樣的代碼,性能提升約2倍左右。Google稱,將Android L最終發布的時候,可以預計的性能提升將會像Chessbench一樣,有3x的加速。

  2 垃圾收集:理論和實踐

  Android虛擬機依賴自動化的內存管理機制,即自動垃圾收集。這一Java語言編程模式的基石也是Android系統自誕生之日起,非常重要的一部分。這裡向不太了解垃圾收集概念的朋友解釋一下,所謂自動垃圾收集,就是說程序員在編程過程中,不需要自己負責物理內存的存儲的分配和釋放。只需要使用固定的模式創建你需要的變量或者對象,然後直接利用該變量或對象即可。程序的運行環境會自動在內存中分配相應的內存空間存儲該變量或者對象, 並在該變量或者對象失效後,自動釋放所分配的內存。這是和其他需要人工進行存儲管理的較低層次語言最大的區別。自動垃圾收集的好處是,程序員不必再在編程時擔心內存管理的問題,當然,這也是有代價的,那就是程序員無法控制內存何時分配和釋放,因而無法在需要時進行優化(Java語言有一些編程接口可以供程序員手工優化程序,但控制方式和粒度有限).

  Android曾經被Dalvik的垃圾收集機制折騰了很久。Android平台的內存普遍較小,每次應用程序需要分配內存,當堆空間(分配給應用程序的一塊內存空間)不能提供如此大小的空間時,Dalvik的垃圾收集器就會啟動。垃圾收集器會遍歷整個堆空間,查看每一個應用程序分配的對象,並對所有可到達的對象(即還會被使用的對象)標記,並將那些沒有標記的對象空間釋放掉。

  在Dalvik虛擬機中,垃圾收集器執行的過程將導致兩次應用程序的停頓:

  一是在遍歷堆地址空間階段,

  另一個是標記階段。

  所謂停頓,即應用程序所有正在執行的進程將暫停。如果停頓時間過長,將會導致應用程序在渲染時出現丟幀現象,進而導致應用程序的卡頓現象,大大降低用戶體驗。

  Google聲稱,在Nexus 5手機上,這種停頓的平均長度在54ms。這個停頓時間將導致平均每次垃圾收集會導致在應用程序渲染顯式時丟掉4幀的。

  我自己的經驗和測試表明,根據應用程序的不同,停頓的時間可能會增大很多。比如,在官方的FIFA應用程序這一典型程序中,垃圾收集的停頓會非常厲害。

  07-01 15:56:14.275: D/dalvikvm(30615): GCFORALLOC freed 4442K, 25% free 20183K/26856K, paused 24ms, total 24ms

  07-01 15:56:16.785: I/dalvikvm-heap(30615): Grow heap (frag case) to 38.179MB for 8294416-byte allocation

  07-01 15:56:17.225: I/dalvikvm-heap(30615): Grow heap (frag case) to 48.279MB for 7361296-byte allocation

  07-01 15:56:17.625: I/Choreographer(30615): Skipped 35 frames! The application may be doing too much work on its main thread.

  07-01 15:56:19.035: D/dalvikvm(30615): GCCONCURRENT freed 35838K, 43% free 51351K/89052K, paused 3ms+5ms, total 106ms

  07-01 15:56:19.035: D/dalvikvm(30615): WAITFORCONCURRENTGC blocked 96ms

  07-01 15:56:19.815: D/dalvikvm(30615): GCCONCURRENT freed 7078K, 42% free 52464K/89052K, paused 14ms+4ms, total 96ms

  07-01 15:56:19.815: D/dalvikvm(30615): WAITFORCONCURRENTGC blocked 74ms

  07-01 15:56:20.035: I/Choreographer(30615): Skipped 141 frames! The application may be doing too much work on its main thread.

  07-01 15:56:20.275: D/dalvikvm(30615): GCFORALLOC freed 4774K, 45% free 49801K/89052K, paused 168ms, total 168ms

  07-01 15:56:20.295: I/dalvikvm-heap(30615): Grow heap (frag case) to 56.900MB for 4665616-byte allocation

  07-01 15:56:21.315: D/dalvikvm(30615): GCFORALLOC freed 1359K, 42% free 55045K/93612K, paused 95ms, total 95ms

  07-01 15:56:21.965: D/dalvikvm(30615): GCCONCURRENT freed 6376K, 40% free 56861K/93612K, paused 16ms+8ms, total 126ms

  07-01 15:56:21.965: D/dalvikvm(30615): WAITFORCONCURRENTGC blocked 111ms

  07-01 15:56:21.965: D/dalvikvm(30615): WAITFORCONCURRENTGC blocked 97ms

  07-01 15:56:22.085: I/Choreographer(30615): Skipped 38 frames! The application may be doing too much work on its main thread.

  07-01 15:56:22.195: D/

copyright © 萬盛學電腦網 all rights reserved