1. 程式人生 > >【朝花夕拾】Android效能優化篇之(五)Android虛擬機器

【朝花夕拾】Android效能優化篇之(五)Android虛擬機器

前言

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

          

        閱讀本文,建議結合筆者之前的兩篇文章,瞭解一下JVM和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資源,電池資源等的目的。