【朝花夕拾】Android性能篇之(五)Android虛擬機

Android虛擬機的使用,使得android應用和Linux內核分離,這樣做使得android系統更穩定可靠,比如程序中即使包含惡意代碼,也不會直接影響系統文件;也提高了跨平臺兼容性。在Android4.4以前的系統中,Android系統均採用Dalvik作爲運行andorid程序的虛擬機,在android發展中具有舉足輕重的地位,而Android 5.0及以後的系統使用ART虛擬機取代Dalvik,在性能上做了很大的優化。本文將對這兩款虛擬機做一些介紹,主要內容如下:

      

    閱讀本文,建議結合筆者之前的兩篇文章,瞭解一下JVM和Apk打包:

    【朝花夕拾】Android性能篇之(一)序言及JVM篇

    【朝花夕拾】Android性能篇之(四)Apk打包

一、什麼是Dalvik?

   Dalvik是Google公司自己設計用於Android平臺的虛擬機,是Android移動設備平臺的核心組成部分之一。虛擬機的概念在前面文章中講到過是,就是一個設備上開闢的一個虛擬空間,一個虛擬出來的設備。Dalvik就是這樣,在android設備上虛擬出來的一個用於運行Android程序的空間。由於Android程序的開發語言是java,所以Dalvik的本質仍然是JVM,是一個特殊設計的JVM,沒有遵循Java虛擬機規範。另外,值得一提的是,Dalvik的命名來源於其祖先生活在冰島的一個叫做Dalvik的小漁村。

二、Dalvik在Android架構中所處的位置

        

   想必讀者們對如上截圖已經相當熟悉了——android系統架構圖。從上圖可以看到,Dalvik虛擬機在Android Runtime中,在Linux Kernel之上。我們都知道,Android其實就是一個操作系統,其底層基於Linxu Kernel,這一層有許多的驅動程序,主要完成操作系統所具備的功能。Android Runtime,即android的運行環境,我們可以類比於java的jre,即java平臺運行期環境。Java程序的開發、編譯和運行需要java的核心包(jdk/lib/和jre/lib)支持,然後通過JVM來運行java程序,同樣android程序的運行也是如此,Libraries就相當於java的jdk/lib,是開發/編譯android程序所需要的庫,Android Runtime裏面的Core Libraries裏就相當於java的jre/lib,是運行android程序所需要的核心庫,自然而然,Dalvik虛擬機也就類比於java中的JVM,用於運行android程序。

三、Dalvik的作用

   簡單來說就是:Dalvik虛擬機在Android操作系統上虛擬出一個設備,用來運行android 應用程序。Dalvik是apk運行的溫牀,其作爲面向Linux、爲嵌入式操作系統特別設計的虛擬機, 主要負責完成對象的生命週期管理、堆棧管理、線程管理、安全及異常管理、垃圾回收等。Dalvik充分利用Linux進程管理的特性,對其進項了面向對象的設計,使得可以同時運行多個程序,而傳統的Java程序通常只能運行一個進程,這也是爲什麼Android不採用JVM的原因之一。在Android中,每一個app進程對應一個Dalvik,多個app進程在運行,就對應多個虛擬機的存在,這樣設計的好處就是,當一個應用crash後,只會影響自己所在的dalvik,而不會影響到整個系統,不同的進程之間(即不同的Dalvik之間)通過進程間通信來實現交互。

四、Dalvik和JVM的區別與聯繫

    Android程序也是用Java語言開發的,所以Dalvik本質上講也是java虛擬機,那麼Dalvik和JVM又有哪些區別和聯繫呢?主要有如下幾點:  

  (1)本質上Dalvik也是JVM,是特殊設計的JVM,沒有遵循java虛擬機設計規範。

  (2)JVM是基於棧的虛擬機,而Dalvik是基於寄存器的虛擬機,對於基於棧和基於寄存器的虛擬機的區別和優缺點,推薦閱讀:基於棧虛擬機和基於寄存器虛擬機的比較,講的簡潔且易懂,咱們這裏不深入展開。

  (3)JVM運行的是Java字節碼文件,即.class文件,而Dalvik運行的是.dex(即Dalvik Executable)文件。.dex是在.class文件的基礎上,經過DEX工具壓縮和優化後形成的。如下圖所示: 

         

    當javac將java程序編譯成class後,dex工具將所有的class文件整合到一個.dex文件中,這樣做使得各個類能夠共享數據,在一定程度上降低了冗餘,同時也使文結構更加緊湊。.dex格式也是專爲Dalvik設計的一種壓縮格式,適合內存和處理器速度有限的系統。實驗表明,dex文件時傳統jar文件的50%左右。下圖爲java .jar包中.class文件和android .apk中.dex文件對比圖:

         

  (4)補充兩個Davik的特徵:

    1)Dalvik經過優化,允許在有限的內存中同時運行多個虛擬機的實例,每一個應用對應一個虛擬機實例,對應了一個進程,對應一個獨立的Linux進程。獨立的進程可以防止在虛擬機崩潰的時候所有程序都被關閉。

    2)Dalvik第一次加載後,會生成Cache文件,以提供下次快速加載,所以第一次會很慢。

五、Davik的孵化器——Zygote進程

   在Android系統中有個一特殊的虛擬機進程Zygote,他是虛擬機實例的孵化器。它在系統啓動的時候就會產生,完成虛擬機的初始化、庫的加載、預製類庫和初始化操作。如果系統需要一個新的虛擬機實例,他會迅速複製自身,以最快的速度提供給系統。對於一些只讀的系統庫,所有的虛擬機實例都和Zygote共享一塊區域。

六、Dalvik的致命缺點:拖慢Android系統速度

   Dalvik有個致命的弱點,就是Dalvik虛擬機一直被用戶指責爲拖慢Android系統運行速度而不如IOS的根源。主要原因如下:

1、開發者因素

   Android起步比IOS晚,平臺不成熟,初期開發者水平有限,對性能方面關注比較少,主要關注點在提供各種豐富多彩的應用上。

2、運營商因素

   Android是開源的,不同的手機廠商往往對android系統進行定製,而各廠商的技術參差不齊,修改後的特性或新增的功能,對原生系統的性能也造成一定的影響。同時,Android比較開放,有些開發者不顧用戶體驗,爲一些目的在後臺做了一些小動作,比如收集用戶信息等,拖慢整體速度。

3、Dalvik運行時機制因素

   在編譯Android程序的時候,首先java代碼被編譯成class文件,然後被java打包工具dx打包成.dex文件,然後.dex文件和資源文件一起被壓縮成apk文件。Apk文件其實也是zip格式,只是後綴被修改爲apk,讀者可以自己解壓一個apk試試看。Android應用的安裝過程:複製apk安裝包到data/app目錄(見截圖6.3.2,截圖6.3.3)下,解壓並掃描安裝包,把dex文件保存到dalvik-cache目錄(見截圖6.3.4)下,並在data/data(見截圖6.3.5)目錄下創建對應的應用數據目錄。這樣每次用戶點擊圖標運行android程序時,dalvik虛擬機就會用JIT(Android2.2及以後版本)的方法把dex文件翻譯爲機器碼,然後再執行機器碼。雖然Dalvik虛擬機已經被做過很多優化(.dex文件基礎上被優化爲.odex文件,o表示optimization,“優化”的意思),但因爲此種機制的存在,先翻譯再執行,所以Android在電量消耗和程序運行流暢程度上一直不太理想。    

   

                                             截圖6.3.1  Android中 /data目錄

   

                                                   截圖6.3.2 /data/app目錄

   
                                     截圖6.3.3   /data/app目錄下應用的信息

   
                                    截圖6.3.4   /data/dalvik-cache目錄下的內容

   
                   截圖6.3.5   /data/data目錄下應用數據目錄,存儲對應應用運行中產生的一些數據

七、ART虛擬機取代Dalvik虛擬機

   在第六點中,我們講到了,由於Dalvik虛擬機機制的問題,拖慢了android應用的速度。由此,ART(即Android RunTime)虛擬機應運而生,在Android4.4中可以在設置中切換選擇Dalvik或ART作爲虛擬機,在Android L(5.0)中就直接刪除了Dalvik,而全面使用ART。ART在機制上做了優化,可以在第一次安裝應用時,字節碼就會預編譯(即AOT編譯:Ahead-of-time)成機器碼,使其成爲真正的本地應用。在點擊桌面的應用圖標運行時,無需再翻譯字節碼,而是直接運行機器碼,從而提升了啓動速度。另外,ART在英語單詞中是“藝術”的意思,可見,ART虛擬機的設計是匠心獨運,同時也是被其設計中所高度讚譽的。

   下圖展示了Dalvik和ART對.dex文件的處理的對比情況:

八、ART的優缺點

1、優點

   ART的AOT方式相比於Dalvik的JIT方式(Just-In-Time,即時編譯,,參見JIT_百度百科),主要由如下的有優勢:

(1)ART拋棄了Dalvik的JIT方式,而採用AOT預編譯方式,在安裝apk的過程中,將.odex文件(.dex優化後的文件)預編譯爲二進制機器碼,存儲在設備中,以後每次啓動應用的時候,直接運行機器碼,而無需再翻譯.odex,這樣極大地提高了應用的啓動速度。

(2)每次運行時所做的工作也少了,這樣佔用了更少的CPU資源,也消耗了更少的電池資源。

(3)ART也在開發者工具和垃圾回收器上做了改善。

         

                         Dalvik和ART在性能上的對比

2、缺點

   硬幣有正反面,ART的預編譯,也帶來了一定的劣勢

(1)增加了安裝時間。在安裝的時候需要預編譯,無疑增大了安裝的工作量,從而增大了安裝時間,對於一些大的應用,可能需要幾分鐘的時間才能安裝完。

(2)需要更多的空間存儲預編譯後的機器碼,無疑佔用了更多的存儲空間。當然,現在硬件設備更新換代很快,性能也非常好,相比於ART帶來的優點,該缺點幾乎沒什麼影響。

九、Android N對ART的優化

   在上一節中我們提到是,ART的機制使得apk在安裝的時候比較耗時,爲了改變這種狀態,在Android N(Android7.0)中對此做了優化。Android N實現了一個使用AOT、解釋、JIT混合模式的運行環境,這裏使用的JIT是改進後的JIT,ART也提供了一種新的、更快的解釋器。這種方式在apk安裝的過程中不再進行預編譯,第一次運行該應用相關程序後,在手機處於idle狀態和充電的時候再將運行過的程序編譯爲機器碼並存儲在設備中。JIT提供了一套追蹤機制來決定哪一部分代碼需要在手機idle和充電的時候來編譯(即熱區域hot method的確定),這個追蹤技術被稱爲Profile Guided Compilation,其工作原理如下:

  (1)應用程序第一次啓動的時候,只會通過解釋器執行,同時JIT會介入並針對hot methods執行優化工作。代碼在執行期間會被分析,分析結果被保存起來,同步輸出一種被稱爲profile information的信息保存到文件中。該文件中記錄了需要離線優化的hot methods,影響程序啓動速度的Classes,它們主要用於進一步優化程序的啓動速度。

  (2)當設備處於idle狀態並且在充電,就會進入Profile Guided Compilation服務,使用第一步中的profile information,生成二進制機器碼,用於替代原始應用程序的相應部分。

  (3)應用程序在後續啓動時,就可以根據實際情況在AOT/JIT/Interpreter中選擇最合適的執行方式了。

    通過以上的步驟可以得知,因爲有了Profile Guided Compilation,同一app會因爲不同的用戶行爲產生不同的編譯結果。

   我們可以概括性地做一個總結:第一次運行到某些模塊的程序的時候(此次JIT信息不會持久化),產生一個文件來記錄這些被執行的程序信息,從而實現了將以往在安裝過程中預編譯生成機器碼的過程,延遲到手機處於idle和充電的時候來完成,最終實現既能避免漫長的安裝等待,又不影響程序啓動速度,還節約了空間(因爲有些功能程序一直不被使用,就不需要編譯爲機器碼佔用空間),cpu資源,電池資源等的目的。 

參考資料

    Android爲什麼比IOS慢?

    Android ART虛擬機執行引擎詳情

    Android7.0開發者版本新特性

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