Android系統作為移動端主流平臺,其高效的虛擬機無疑是其核心競爭力之一。今天,就讓我們一起剝開Dalvik和ART虛擬機的外衣,深入解析它們的工作原理和優缺點,幫助你全面把握Android系統的運行機制。
正文導覽
- Dalvik和ART虛擬機的發展歷程
- Dalvik虛擬機的工作原理和特點
- ART虛擬機的工作原理和優勢
- 兩者的性能和效率對比分析
- 如何根據需求選擇合適的虛擬機
一、Dalvik和ART的發展歷史
1、 Dalvik孕育與興起
Dalvik在2007年隨著Android平臺的發布而首次亮相,并在隨后的幾年中不斷更新和改進。
它基于開源的Java虛擬機,但做了很多改進和優化,專門為搭載有限資源的移動設備量身定制,如:
- Register-based執行,減少內存占用
- .dex字節碼格式,減小APK體積
- JIT即時編譯器,提升運行效率
Dalvik虛擬機(DVM)與傳統的Java虛擬機(JVM)有幾個關鍵的區別:
- 設計目標:Dalvik被設計為適合移動設備,具有較低的內存占用和高效的電池使用。
- 執行格式:Dalvik使用
.dex
文件格式,這是從Java字節碼轉換而來的一種壓縮形式,專為Dalvik優化。 - 垃圾回收:Dalvik采用了一套適合移動設備的垃圾回收機制,以適應有限的資源。
(1)、Dalvik的主要功能和作用包括
- 執行Android應用程序:Dalvik虛擬機執行
.dex
格式的應用程序代碼。 - 內存管理:Dalvik提供了一套適合移動設備的內存管理策略。
- 垃圾回收:Dalvik的垃圾回收機制優化了移動設備的資源使用。
(2)、Dalvik的優點
-
資源占用低:Dalvik設計時考慮了移動設備的資源限制,占用較少的內存和處理能力。
-
靈活性:Dalvik允許更多的定制和優化,以適應不同的硬件和軟件環境。
(3)、Dalvik的缺點
-
性能限制:由于依賴運行時編譯,Dalvik的性能可能不如AOT編譯的ART。
-
內存管理:雖然針對移動設備進行了優化,但在某些情況下,Dalvik的內存管理可能不如ART高效。
2 、ART繼任登場
伴隨硬件性能的飛速提升,Dalvik的一些先天缺陷逐漸凸顯,主要表現為應用啟動緩慢、無法實現應用級別的JIT等。為了持續提升性能,Google從Android 4.4開始引入全新的ART虛擬機。
ART本質上是一款Ahead-Of-Time (AOT)編譯器,它在應用安裝時就預先編譯字節碼為機器碼,這使得應用的啟動和運行速度都得到極大提升。Android 8.0及更高版本已經將ART設為默認虛擬機。
(1)、ART的主要改進包括
- Ahead-of-Time(AOT)編譯:ART采用了AOT編譯技術,將應用程序代碼在安裝時編譯成機器碼,從而提高了執行效率。
- 性能提升:由于AOT編譯,ART在運行時不需要進行即時編譯(JIT),這減少了運行時的開銷,提高了性能。
- 內存管理:ART改進了內存分配和垃圾回收機制,提供了更好的內存管理。
(2)、ART的主要功能和作用包括
- AOT編譯:ART在安裝時將應用程序代碼編譯成機器碼,提高了啟動速度和運行效率。
- 性能優化:ART通過減少運行時編譯的需要,提高了應用程序的性能。
- 內存管理:ART提供了改進的內存管理機制,包括更有效的垃圾回收。
(3)、ART的優點
-
性能提升:ART通過AOT編譯提供了更好的性能。
-
內存管理:ART的內存管理更為高效,特別是在處理大型應用程序時。
(4)、ART的缺點
- 安裝時間:由于AOT編譯,應用程序的安裝時間可能會更長。
- 兼容性問題:某些舊的Android應用程序可能需要額外的工作才能在ART上運行。
二、Dalvik虛擬機工作原理
Dalvik虛擬機通過其獨特的設計和優化措施,為Android應用提供了高效的運行環境。然而,隨著Android系統的發展,Dalvik最終被ART(Android RunTime)所取代,后者提供了更高的性能和更好的內存管理。盡管如此,了解Dalvik的工作原理對于理解Android應用開發的歷史和演變仍然非常重要。
下面我們來看看 Dalvik虛擬機的工作原理:
1、基于寄存器的架構
Dalvik虛擬機采用的是基于寄存器的架構,不同于傳統的基于棧的Java虛擬機。這種設計使得Dalvik虛擬機的執行效率更高,因為它減少了指令的數量和復雜性。
2、.dex文件格式
Dalvik虛擬機使用.dex
文件格式來存儲和執行應用程序代碼。.dex
格式是專門為Dalvik設計的壓縮格式,它由dx
工具從Java的.class
文件轉換而來,優化了存儲空間和訪問速度。
3、Zygote進程
Dalvik虛擬機有一個特殊的Zygote進程,它作為虛擬機實例的孵化器。在系統啟動時,Zygote進程會創建并完成虛擬機的初始化、庫的加載和預置類庫的初始化操作。當系統需要一個新的虛擬機實例時,Zygote可以迅速復制自身,以最快的速度提供給系統。
4、內存共享
Dalvik虛擬機允許多個虛擬機實例共享一些只讀的系統庫,這意味著所有虛擬機實例都和Zygote共享一塊內存區域。這有助于減少內存占用并提高效率。
5、JIT編譯技術
自Android 2.2開始,Dalvik虛擬機支持JIT(Just-In-Time,即時編譯技術)。這意味著虛擬機可以在運行時對代碼進行編譯,進一步提高執行效率。
6、優化措施
Dalvik虛擬機在安裝到移動設備時,可執行文件可能會被修改以進一步優化性能。這包括調整數據的端序、內聯一些函數和簡化結構體,以及短路掉一些不必要的操作。
7、代碼監控與優化
當Android啟動時,Dalvik VM監視所有的程序(APK),并創建依存關系樹,為每個程序優化代碼并存儲在Dalvik緩存中。這意味著第一次加載應用時可能會較慢,因為需要生成緩存文件,但之后加載會更快。
8、快速翻譯器
Dalvik還提供了一個快速翻譯器(Fast Interpreter)來強化功能,這有助于提高代碼的解釋執行速度。
9、與Java SE/ME的區別
Dalvik虛擬機不支持Java SE或Java ME類庫,它使用自己建立的類庫,這是Apache Harmony Java的一個子集。這使得Dalvik能夠為Android提供定制化的運行時環境。
10、許可與版權
Dalvik是基于Apache License 2.0發布的,Google聲稱Dalvik是一個清潔室(clean room)的實現,不是基于標準Java運行環境的改進,因此不受標準Java運行環境版權許可的限制。
三、ART虛擬機的運行機制
1 、AOT靜態編譯機制
在Android開發中,AOT(Ahead-Of-Time)編譯是一種在應用安裝之前,將Java代碼編譯成機器碼的技術。AOT編譯可以提高應用的啟動速度和性能,因為它減少了應用運行時的即時編譯(JIT)需求。
從Android Studio 3.3開始,Android引入了D8 Dexer來替代舊的Dex編譯器,并且從Android 9(Pie)開始,Android引入了新的AOT編譯器,使得AOT編譯成為默認行為。
下面是一個簡單的Android Java代碼示例,以及如何在Android Studio中構建和理解AOT編譯的運行過程:
(1)、創建Android項目
打開Android Studio,創建一個新的Android項目。
(2)、編寫Java代碼
在MainActivity.java中編寫示例代碼:
package com.example.aotdemo;import android.os.Bundle;
import android.widget.TextView;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView textView = findViewById(R.id.text_view);textView.setText("Hello, AOT World!");}
}
(3)、 構建APK
在Android Studio中,你可以通過點擊Build
菜單然后選擇Build Bundle(s) / APK(s)
來構建APK。對于AOT編譯,你可以選擇構建一個Release版本的APK。
(4)、理解AOT編譯過程
當你構建Release版本的APK時,以下步驟發生:
-
D8 Dexer:首先,D8將Java字節碼轉換為Dalvik字節碼,這是一種中間表示形式,專為Android設計。
-
AOT編譯器:然后,Android的AOT編譯器將Dalvik字節碼編譯成機器碼。這個過程發生在應用安裝之前,因此當應用運行時,大部分代碼已經是機器碼,減少了運行時的JIT編譯需求。
(5)、 安裝APK
將構建的APK安裝到Android設備或模擬器上。
(6)、運行應用
運行應用,你將看到"Hello, AOT World!"的文本顯示在屏幕上。
(7)、 查看編譯結果
要查看AOT編譯的結果,可以使用adb
命令行工具來查看設備上的ELF文件,這些文件包含了編譯后的機器碼:
adb shell
cd /data/app/
ls -l <package_name>
替換<package_name>
為你的應用包名。你將看到一些以.oat
結尾的文件,這些文件包含了AOT編譯后的機器碼。
(8)、注意事項
- AOT編譯是Android系統自動處理的,開發者通常不需要手動干預。
- AOT編譯可以提高應用的性能,特別是在應用啟動時。
- 由于AOT編譯在安裝前進行,因此它可以減少應用運行時的資源消耗。
通過上述步驟,你可以在Android Studio中構建一個應用,并理解AOT編譯的基本概念和運行過程。
2 、Ahead-Of-Time編譯器
Ahead-Of-Time(AOT)編譯器是一種靜態編譯器,它在程序執行之前將高級語言代碼(如Java或C/C++)轉換為機器碼。這種編譯方式允許編譯器進行深入的分析和優化,因為編譯器有足夠的時間來執行這些操作,并且不需要在運行時進行即時編譯(JIT)。
以下是AOT編譯器在編譯過程中執行的一些關鍵優化步驟:
(1)、內聯(Inlining)
內聯是一種優化技術,它涉及將函數調用的代碼直接嵌入到調用點,從而消除函數調用的開銷。這在調用小型函數時特別有效,因為函數調用的開銷可能比函數本身執行的時間還要長。AOT編譯器會分析函數調用的上下文,并決定是否內聯這些函數。
(2)、去虛擬化(Devirtualization)
在面向對象的編程中,虛擬函數調用(通過虛函數表)可能會引入運行時開銷。AOT編譯器可以分析程序的類型信息,并在可能的情況下將虛擬函數調用轉換為直接函數調用,從而消除虛函數表的查找過程。
(3)、寄存器分配(Register Allocation)
寄存器分配是編譯過程中的一個關鍵步驟,它涉及將程序中的變量分配給CPU的寄存器。AOT編譯器會嘗試優化寄存器的使用,以減少內存訪問的需要,從而提高程序的執行速度。
(4)、死代碼消除(Dead Code Elimination)
死代碼消除是一種優化技術,它涉及識別并移除程序中永遠不會執行的代碼。這可以減少生成的機器碼的大小,提高程序的效率。
(5)、常量傳播(Constant Propagation)
常量傳播涉及在編譯時將表達式中的常量值傳播到它們被使用的每個地方。這可以簡化運行時的計算,并可能使進一步的優化成為可能。
(6)、循環優化(Loop Optimization)
循環是許多程序中性能的關鍵部分。AOT編譯器可以執行各種循環優化,如循環展開(將循環的多次迭代合并為一個迭代),循環融合(將多個循環合并為一個循環),以及循環不變代碼的移動。
(7)、指令調度(Instruction Scheduling)
指令調度涉及重新排列指令的順序,以優化CPU流水線的使用。這可以減少指令執行的等待時間,提高程序的執行效率。
(8)、代碼生成(Code Generation)
在這個階段,AOT編譯器將優化后的中間表示(IR)轉換成目標機器的指令。這個過程涉及選擇最合適的機器指令來實現高級操作,并確保生成的代碼符合目標平臺的架構要求。
(9)、鏈接(Linking)
最后,AOT編譯器將生成的機器碼與庫和其他依賴項鏈接在一起,生成最終的可執行文件。
AOT編譯器的這些優化可以顯著提高程序的性能,尤其是在啟動時間和運行時性能方面。然而,這些優化也可能增加編譯時間,并可能導致生成的可執行文件體積增大。此外,由于AOT編譯是在沒有運行時信息的情況下進行的,因此某些優化可能不如JIT編譯那樣精確。盡管如此,AOT編譯仍然是許多高性能應用程序的首選方法,特別是在嵌入式系統、移動設備和游戲開發中。
3 、支持多種GC算法
ART可以選擇標記-清除、標記-整理或并發標記掃描等多種GC算法,并根據運行時狀況進行切換。
(1)、ART中常見的幾種GC算法
-
標記-清除(Mark-Sweep)
標記-清除是最基礎的垃圾收集算法之一。它分為兩個階段:
- 標記階段:垃圾收集器遍歷所有可達對象,并標記它們為活躍的。
- 清除階段:垃圾收集器再次遍歷堆內存,清除所有未被標記的對象。
這種算法簡單,但有兩個主要問題:一是它不能處理循環引用,二是它會產生內存碎片。
-
標記-整理(Mark-Compact)
為了解決標記-清除算法中的問題,標記-整理算法在標記階段之后增加了一個整理階段:
-
整理階段:垃圾收集器移動活躍對象,使它們緊密排列,從而減少內存碎片。
這種算法可以減少內存碎片,但會增加GC的暫停時間,因為對象需要被移動。
-
-
并發標記掃描(Concurrent Mark-Sweep or Concurrent Marking)
并發標記掃描算法嘗試減少垃圾收集對應用程序性能的影響,通過在應用程序運行時并發地執行標記階段:
- 并發標記階段:垃圾收集器在應用程序運行時并發地遍歷對象圖,標記活躍對象。
- 暫停標記階段:在應用程序暫停時,完成標記過程,并執行清除或整理。
這種算法可以減少GC引起的應用程序暫停時間,但實現復雜,需要處理并發訪問和修改對象的問題。
-
分代收集(Generational Collection)
ART還實現了分代收集策略,它基于這樣一個觀察:大多數對象都是短暫存在的。分代收集將堆內存分為幾個區域,每個區域代表不同的對象生命周期(年輕代、老年代等):
-
年輕代收集:頻繁地對年輕代進行垃圾收集,因為大多數新創建的對象都會很快變成垃圾。
-
老年代收集:較少地對老年代進行垃圾收集,因為存活下來的對象通常活得更久。
-
-
增量收集(Incremental Collection)
增量收集算法嘗試將垃圾收集工作分散到多個小步驟中,以減少每次GC的暫停時間。
-
增量步驟
垃圾收集器在多個小的、增量步驟中執行標記、清除或整理工作。這種方法可以減少單次GC引起的延遲,但可能會增加整體的GC時間。
(2)、運行時切換
ART可以根據應用程序的行為和性能需求動態地在不同的GC算法之間切換。例如:
- 當檢測到內存使用率較高或GC暫停時間過長時,ART可能會從標記-清除切換到標記-整理,以減少內存碎片。
- 在應用程序負載較低時,ART可能會使用并發標記掃描,以減少對應用程序性能的影響。
- 對于具有大量短暫對象的應用程序,ART可能會采用分代收集策略。
ART的垃圾收集器是高度可配置的,開發者可以通過設置特定的調試選項或使用Android Profiler等工具來監控和調整GC行為,以優化應用程序的性能。
4、 BCP 技術性能優化
BCP(Background Compact Profiling)是Android Runtime (ART) 引入的一項技術,它主要目的是在后臺對Android應用程序的內存使用進行分析和優化,從而提高應用程序的性能和響應速度。以下是BCP的一些關鍵功能和作用:
(1)、內存分析
BCP可以在應用程序運行時,對內存中的活動對象進行分析,識別出哪些對象是活躍的,哪些對象是可以被回收的垃圾。這種分析是在后臺進行的,不會影響應用程序的正常使用。
(2)、內存優化
通過分析內存使用情況,BCP可以識別出內存中的碎片和浪費,然后通過垃圾收集(GC)來回收不再使用的對象,釋放內存空間。這有助于減少內存使用,防止內存泄漏。
(3)、減少GC暫停時間
BCP通過在后臺進行垃圾收集,可以減少應用程序運行時的GC暫停時間。這對于提高應用程序的響應性和用戶體驗非常重要,因為用戶不喜歡看到應用程序在執行任務時出現卡頓。
(4)、內存碎片整理
隨著應用程序的運行,內存中的對象可能會被刪除,導致內存碎片化。BCP可以識別這些碎片,并在后臺進行內存整理,使得內存空間更加連續,從而提高內存的使用效率。
(5)、應用性能監控
BCP不僅可以優化內存使用,還可以監控應用程序的性能。它可以幫助開發者了解應用程序在運行時的行為,識別性能瓶頸和潛在問題。
(6)、支持熱更新
雖然BCP本身不直接提供熱更新功能,但它可以與熱更新機制相結合,使得熱更新后的代碼可以在后臺進行優化,從而在用戶不感知的情況下提高更新后代碼的性能。
( 7)、提高系統穩定性
通過及時回收不再使用的對象和優化內存使用,BCP有助于提高整個系統的穩定性。它減少了因內存不足導致的應用程序崩潰或系統錯誤。
(8)、后臺執行
BCP的所有操作都是在后臺執行的,這意味著它不會干擾用戶當前的操作或應用程序的運行。這種非侵入式的優化對于提升用戶體驗至關重要。
BCP是ART中一項重要的技術,它通過在后臺對內存進行分析和優化,顯著提高了Android應用程序的性能和穩定性。它減少了垃圾收集的暫停時間,優化了內存使用,并支持了熱更新機制,使得應用程序可以在不重啟的情況下進行更新和優化。這些功能共同作用,為用戶提供了更加流暢和響應迅速的Android體驗。
四、Dalvik vs ART的效率對比
相較于Dalvik,ART在很多方面都有了質的提升:
- 應用啟動速度 - 由于AOT編譯,ART應用啟動速度快2-4倍
- 執行效率 - 優化的機器碼使ART執行效率高30%以上
- 內存使用 - 更好的GC算法令ART內存使用更高效
- 電池續航 - ART對電池續航性能略有提升
當然,AOT編譯的靜態系統也帶來了一些缺點,比如占用更多存儲空間、熱更新部署不便等。總的來說,ART在絕大多數場景下都表現更佳。
五、如何根據需求選擇合適的虛擬機
對于普通的Android應用,用戶無需過多考慮虛擬機的選擇,只需遵循Google的最新推薦即可,目前就是使用ART。
而對于某些嵌入式或專用場景的Android設備,如Android TV、Android Auto、IoT等,由于它們存儲和運行環境的特殊性,倒可能需要考慮回退到Dalvik虛擬機。
此外,如果您的應用對存儲空間極為敏感,也可以考慮暫時使用Dalvik,但這種做法并不推薦,因為它犧牲了性能換取的存儲空間優勢并不太值。
展望未來
通過本文,相信您已經對Android兩大虛擬機有了全面的理解。不過,技術發展日新月異,虛擬機的優化和創新從未停止腳步。比如說,未來Android或許會加入iOS的Bitcode技術;谷歌也在積極研究機器學習算法在ART優化中的應用等。
虛擬機作為系統的核心基礎,我們當然有必要時刻關注其最新發展動向。如您還有任何疑問或心得,也歡迎在評論區繼續交流討論。