1. 程式人生 > >小白理解安卓虛擬機器以及華為的'諾亞方舟'

小白理解安卓虛擬機器以及華為的'諾亞方舟'

虛擬機器,提到虛擬機器,大家可能第一反應就是java中好像有虛擬機器這個玩意。但是安卓中的虛擬機器是什麼呢?是和java一樣的嗎?那麼我們先來了解一下java中的JVM!

JVM,搞java的肯定對它瞭解不少。JVM本質上就是一個軟體,是計算機硬體的一層軟體抽象,在這之上才幹夠執行Java程式,JAVA在編譯後會生成相似於組合語言的JVM位元組碼,與C語言編譯後產生的組合語言不同的是,C編譯成的組合語言會直接在硬體上跑。但JAVA編譯後生成的位元組碼是在JVM上跑,須要由JVM把位元組碼翻譯成機器指令。才幹使JAVA程式跑起來。JVM執行在作業系統上,遮蔽了底層實現的差異。從而有了JAVA吹噓的平臺獨立性和Write Once Run Anywhere。依據JVM規範實現的詳細虛擬機器有幾十種,主流的JVM包括Hotspot、Jikes RVM等。都是用C/C++和彙編編寫的,每一個JRE編譯的時候針對每一個平臺編譯。因此下載JRE(JVM、Java核心類庫和支援檔案)的時候是分平臺的,JVM的作用是把平臺無關的.class裡面的位元組碼翻譯成平臺相關的機器碼,來實現跨平臺。

說白了,簡單點,就是:

                                                                      Java

                                                                      .java檔案 -> .class檔案 -> .jar檔案

最後執行是class檔案,有的會被再次打包成jar檔案。

瞭解了這些之後,我們再去了解Android 中的虛擬機器。

一、Dalvik虛擬機器

Dalvik虛擬機器( Dalvik Virtual Machine ),簡稱Dalvik VM或者DVM。這就是Android中的虛擬機器。最初它的產生,是因為Google為了解決與Oracle之間關於Java相關專利和授權的糾紛,開發了DVM。

Android既然存在虛擬機器,肯定也是在這個DVM上執行的。它的執行流程和JVM很像:

                                                                       Android

                                                                      .java檔案 –> .class檔案 -> .dex檔案->.apk

DVM執行的是.dex格式檔案,JVM執行的是.class檔案,android程式編譯完之後生產.class檔案,然後,dex工具會把.class檔案處理成.dex檔案,然後把資原始檔和.dex檔案等打包成.apk檔案,apk就是android package的意思。

除了上面所說的,專利授權的原因除外,其實還有因為如下原因:

    dvm是基於暫存器的虛擬機器,而jvm是基於虛擬棧的虛擬機器。暫存器存取速度比棧快得多,dvm可以根據硬體實現最大的優化,比較適合移動裝置。

    class檔案存在很多的冗餘資訊,dex工具會去除冗餘資訊,並把所有的.class檔案整合到.dex檔案中,減少了I/O操作,提高了類的查詢速度。

不光是上面這些差異,還有執行環境。  

   Dalvik : 一個應用啟動都執行一個單獨的虛擬機器執行在一個單獨的程序中

   JVM: 只能執行一個例項, 也就是所有應用都執行在同一個JVM中

 

 這個是早先的安卓虛擬機器,執行速度還是相當慢的。基於暫存器的虛擬機器允許更快的執行時間,但代價是編譯後的程式更大。於是新的Dex位元組碼格式odex產生了。它的作用等同於dex,只不過是dex優化後的格式。在App安裝的過程中,會通過Socket向/system/bin/install程序傳送dex_opt的指令,對Dex檔案進行優化。在DexClassLoader動態載入Dex檔案時,也會進行Dex的優化,形成odex檔案。

 

為了適應硬體速度的提升,隨後在Android 2.2的DVM中加入了JIT 編譯器(Just-In-Time Compiler)。Dalvik 使用 JIT 進行即時編譯,藉助 Java HotSpot VM,JIT 編譯器可以對執行次數頻繁的 dex/odex 程式碼進行編譯與優化,將 dex/odex 中的 Dalvik Code(Smali 指令集)翻譯成相當精簡的 Native Code 去執行,JIT 的引入使得 Dalvik 的效能提升了 3~6 倍。

JIT編譯器的引入,提升了安裝速度,減少了佔用的空間,但隨之帶來的問題就是:多個dex載入會非常慢;JIT中的直譯器解釋的位元組碼會帶來CPU和時間的消耗;還有熱點程式碼的Monitor一直在執行帶來電量的損耗。

 

 這種情況下,手機動不動就卡是難以避免的。相信各位如果那時候用著Android手機,一定印象非常深刻。因為並不是那麼好用。

這樣的狀況一直持續到Andorid 4.4,帶來了全新的虛擬機器執行環境 ART(Android RunTime)的預覽版和全新的編譯策略 AOT(Ahead-of-time)。但那時候。 ART 是和 Dalvik 共存的,使用者可以在兩者之間進行選擇(感覺很奇怪,作為一個愛好者,我當時看到這個東西可以切換都是不曉得是什麼玩意,使用者可都是小白啊,沒有必要共存的吧)。在Android 5.0的時候,ART 全面取代 Dalvik 成為 Android 虛擬機器執行環境,至此。Dalvik 退出歷史舞臺,AOT 也成為唯一的編譯模式。

二、ART 

AOT 和 JIT 的不同之處在於:JIT 是在執行時進行編譯,是動態編譯,並且每次執行程式的時候都需要對 odex 重新進行編譯;而 AOT 是靜態編譯,應用在安裝的時候會啟動 dex2oat 通過靜態編譯的方式,來將所有的dex檔案(包括Multidex)編譯oat檔案,編譯完後的oat其實是一個標準的ELF檔案,只是相對於普通的ELF檔案多加了oat data section以及oat exec section這兩個段而已。(這兩個段裡面主要儲存了兩種資訊:Dex的檔案資訊以及類資訊和Dex檔案編譯之後的機器碼)。預編譯成 ELF 檔案,每次執行程式的時候不用重新編譯,是真正意義上的本地應用。執行的檔案格式也從odex轉換成了oat格式。

 

其實在Android5.0的時候我們能夠明顯感覺手機好用很多就是因為這個原因,從根本上換掉了那種存在著無法解決弊端的虛擬機器。在 Android 5.x 和 6.x 的機器上,系統每次 OTA 升級完成重啟的時候都會有個應用優化的過程,這個過程就是剛才所說的 dex2oat 過程,這個過程比較耗時並且會佔用額外的儲存空間。

AOT 模式的預編譯解決了應用啟動和執行速度和耗資源(電等)問題的同時也帶來了另外兩個問題:

      1、應用安裝和系統升級之後的應用優化比較耗時,並且會更耗時間。因為系統和apk都是越來越大的。

      2、優化後的檔案會佔用額外的儲存空間

在經過了兩個Android大版本的穩定後,在Android7.0又再次迎來了JIT的 迴歸。

JIT的迴歸,可不是把AOT模式給取代了,而是形成 了AOT/JIT 混合編譯模式,這種模式至今仍在使用。

應用在安裝的時候 dex 不會被編譯。

應用在執行時 dex 檔案先通過解析器(Interpreter)後會被直接執行(這一步驟跟 Android 2.2 - Android 4.4之前的行為一致),與此同時,熱點函式(Hot Code)會被識別並被 JIT 編譯後儲存在 jit code cache 中並生成 profile 檔案以記錄熱點函式的資訊。

手機進入 IDLE(空閒) 或者 Charging(充電) 狀態的時候,系統會掃描 App 目錄下的 profile 檔案並執行 AOT 過程進行編譯。

(Profile檔案會在JIT執行的過程中生成:每個APP都會有自己的Profile檔案,儲存在App本身的Local Storage中。Profile會儲存所呼叫的類以及函式的Index,通過profman工具進行分析生成)

 

 

個人理解:哪種模式擅長幹什麼就讓他去幹什麼。

混合編譯模式綜合了 AOT 和 JIT 的各種優點,使得應用在安裝速度加快的同時,執行速度、儲存空間和耗電量等指標都得到了優化。

之前一直在說流暢,真的流暢在Android7.0上才感受到了些許。Android7.0系統也被用了相當長的一段時間。之後的Android8.0和Android9.0都是對各方面的優化,例如編譯檔案、編譯器、GC。。

其中,值得一提的是華為的方舟編譯器。

  • 首先會判斷該裝置支不支援方舟編譯器,如果支援,則從應用商店下發方舟版本的包
  • 方舟編譯器會把dex檔案通過自己的IR翻譯方舟格式的機器碼,據資料說也是一個ELF檔案,但是會增加一些段,猜測是Dex中類資訊相關的段
  • 通過這種方式,來消除Java與JNI之間的通訊的損耗,以及提升執行時的效率
  • 在方舟內部,還重新完善了GC演算法,使得GC的頻率大大降低,減少應用卡頓的現象
  • 目前方舟只支援64位的So,並且對於加殼的So會出現一些問題。

方舟編譯器適配的應用,下載手機上都是方舟版本的包,特製的包用方舟編譯器編譯效率大大提升,之後直接執行就可以了,直接略過了在ART虛擬機器上預編譯的過程。這樣的結果是很完美的,但是卻也沒辦法跳過一個弊端。那就是生態。還是不管是安卓還是iOS,這麼多年的時間沉澱中,他們的生態系統早就達到了一個非常完善的地步。安卓和iOS應用已經多達上千萬,而方舟適配應用的數量還非常有限。

谷歌宣佈將停止對華為提供安卓系統更新之後,華為曝光了自主研發的鴻蒙作業系統。當時網友各種力挺。不過後來,華為董事長樑華在談及鴻蒙系統時稱,鴻蒙系統是為物聯網開發的,用於自動駕駛、遠端醫療等低時延場景。鴻蒙系統是不是兩手準備我們不得而知。但是,一個作業系統最重要的就是它的生態環境。縱觀華為現在的整個格局,目的非常明確,用方舟編譯器來擴大自己的使用者群體。當用戶的基數足夠龐大時,可以隨時隨地建立一個完善的生態系統。如果在未來某一天,Android全面限制華為的使用之後,在這危機關頭鴻蒙系統還是很有可能扛起國產手機的一面大旗。哪怕不是鴻蒙,我們也需要這樣一個生態不是嗎?

最初,突然去了解Android中的虛擬機器,一個是想要明白到底Android中的虛擬機器和JVM是不是一回事,還有就是想要明白華為釋出方舟編譯器到底快到了哪裡。

上述相關資料均來自網路,侵權必刪。