Android虛擬機(jī)與類加載機(jī)制詳情
JVM與Dalvik
Android應(yīng)用程序運(yùn)行在Dalvik/ART虛擬機(jī),并且每一個(gè)應(yīng)用程序?qū)?yīng)有一個(gè)單獨(dú)的Dalvik虛擬機(jī)實(shí)例。Dalvik虛擬機(jī)實(shí)則也算是一個(gè)Java虛擬機(jī),只不過它執(zhí)行的不是class文件,而是dex文件。 Dalvik虛擬機(jī)與Java虛擬機(jī)共享有差不多的特性,差別在于兩者執(zhí)行的指令集是不一樣的,前者的指令集是基本寄存器的,而后者的指令集是基于堆棧的。

JMV基于棧,Dalvik基于寄存器
基于棧的虛擬機(jī)
對(duì)于基于棧的虛擬機(jī)來說,每一個(gè)運(yùn)行時(shí)的線程,都有一個(gè)獨(dú)立的棧。棧中記錄了方法調(diào)用的歷史,每有一次方法調(diào)用,棧中便會(huì)多一個(gè)棧楨。最頂部的棧楨稱作當(dāng)前棧楨,其代表著當(dāng)前執(zhí)行的方法。基于棧的虛擬機(jī)通過操作數(shù)棧進(jìn)行所有操作。

字節(jié)碼指令
在Androidstudio中搜索ASMPlugin,可以直接用這個(gè)插件查看字節(jié)碼


執(zhí)行過程

基于寄存器的虛擬機(jī)
寄存器
寄存器是CPU的組成部分。寄存器是有限存貯容量的高速存貯部件,它們可用來暫存指令、數(shù)據(jù)和位址。

基于寄存器的虛擬機(jī)
基于寄存器的虛擬機(jī)中沒有操作數(shù)棧,但是有很多虛擬寄存器。其實(shí)和操作數(shù)棧相同,這些寄存器也存放在運(yùn)行時(shí)棧中,本質(zhì)上就是一個(gè)數(shù)組。與JVM相似,在Dalvik VM中每個(gè)線程都有自己的PC和調(diào)用棧,方法調(diào)用的活動(dòng)記錄以幀為單位保存在調(diào)用棧上。

與JVM版相比,可以發(fā)現(xiàn)Dalvik版程序的指令數(shù)明顯減少了,數(shù)據(jù)移動(dòng)次數(shù)也明顯減少了。
ART與Dalvik
Dalvik虛擬機(jī)執(zhí)行的是dex字節(jié)碼,解釋執(zhí)行。從Android 2.2版本開始,支持JIT及時(shí)編譯(Just In Time)在程序運(yùn)行的過程中進(jìn)行選擇熱點(diǎn)代碼(經(jīng)常執(zhí)行的代碼)進(jìn)行編譯或者優(yōu)化。 而ART(Android Runtime) 是在 Android 4.4 中引入的一個(gè)開發(fā)者選項(xiàng),也是 Android 5.0 及更高版本的默認(rèn) Android 運(yùn)行時(shí)。ART虛擬機(jī)執(zhí)行的是本地機(jī)器碼。Android的運(yùn)行時(shí)從Dalvik虛擬機(jī)替換成ART虛擬機(jī),并不要求開發(fā)者將自己的應(yīng)用直接編譯成目標(biāo)機(jī)器碼,APK仍然是一個(gè)包含dex字節(jié)碼的文件。那么,ART虛擬機(jī)執(zhí)行的本地機(jī)器碼是從哪里來?
dex2aot
Dalvik下應(yīng)用在安裝的過程,會(huì)執(zhí)行一次優(yōu)化,將dex字節(jié)碼進(jìn)行優(yōu)化生成odex文件。而Art下將應(yīng)用的dex字節(jié)碼翻譯成本地機(jī)器碼的最恰當(dāng)AOT時(shí)機(jī)也就發(fā)生在應(yīng)用安裝的時(shí)候。ART 引入了預(yù)先編譯機(jī)制(Ahead Of Time),在安裝時(shí),ART 使用設(shè)備自帶的 dex2oat 工具來編譯應(yīng)用,dex中的字節(jié)碼將被編譯成本地機(jī)器碼。

odex的目的:預(yù)先提取,減少RAM的占用,因?yàn)闆]有odex的話,系統(tǒng)要從apk包中提取dex再運(yùn)行。
dexopt與dexaot
- dexopt:在Dalvik中虛擬機(jī)在加載一個(gè)dex文件時(shí),對(duì) dex 文件 進(jìn)行 驗(yàn)證 和 優(yōu)化的操作,其對(duì) dex 文件的優(yōu)化結(jié)果變成了 odex(Optimized dex) 文件,這個(gè)文件和 dex 文件很像,只是使用了一些優(yōu)化操作碼。
- dex2oat:ART 預(yù)先編譯機(jī)制,在安裝時(shí)對(duì) dex 文件執(zhí)行AOT 提前編譯操作,編譯為OAT(實(shí)際上是ELF文件)可執(zhí)行文件(機(jī)器碼)。
Android N的運(yùn)作方式
ART 使用預(yù)先 (AOT) 編譯,并且從 Android N混合使用AOT編譯,解釋和JIT。 1、最初安裝應(yīng)用時(shí)不進(jìn)行任何 AOT 編譯(安裝又快了),運(yùn)行過程中解釋執(zhí)行,對(duì)經(jīng)常執(zhí)行的方法進(jìn)行JIT,經(jīng)過 JIT 編譯的方法將會(huì)記錄到Profile配置文件中。 2、當(dāng)設(shè)備閑置和充電時(shí),編譯守護(hù)進(jìn)程會(huì)運(yùn)行,根據(jù)Profile文件對(duì)常用代碼進(jìn)行 AOT 編譯。待下次運(yùn)行時(shí)直接使用。

ClassLoader
介紹
任何一個(gè) Java 程序都是由一個(gè)或多個(gè) class 文件組成,在程序運(yùn)行時(shí),需要將 class 文件加載到 JVM 中才可以使用,負(fù)責(zé)加載這些 class 文件的就是 Java 的類加載機(jī)制。ClassLoader 的作用簡單來說就是加載 class 文件,提供給程序運(yùn)行時(shí)使用。每個(gè) Class 對(duì)象的內(nèi)部都有一個(gè) classLoader 字段來標(biāo)識(shí)自己是由哪個(gè)ClassLoader 加載的。

ClassLoader是一個(gè)抽象類,而它的具體實(shí)現(xiàn)類主要有:
- BootClassLoader:用于加載Android Framework層class文件。
- PathClassLoader:用于Android應(yīng)用程序類加載器??梢约虞d指定的dex,以及jar、zip、apk中的classes.dex
- DexClassLoader:用于加載指定的dex,以及jar、zip、apk中的classes.dex
很多博客里說PathClassLoader只能加載已安裝的apk的dex,其實(shí)這說的應(yīng)該是在dalvik虛擬機(jī)上。但現(xiàn)在一般不用關(guān)心dalvik了。
Log.e(TAG, "Activity.class 由:" + Activity.class.getClassLoader() +" 加載"); Log.e(TAG, "MainActivity.class 由:" + getClassLoader() +" 加載"); //輸出: Activity.class 由:java.lang.BootClassLoader@d3052a9 加載 MainActivity.class 由:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.enjoy.enjoyfix-1/base.apk"],nativeLibraryDirectories= [/data/app/com.enjoy.enjoyfix-1/lib/x86, /system/lib, /vendor/lib]]] 加載

ClassLoader加載流程與雙親委托機(jī)制
可以看到創(chuàng)建 ClassLoader 需要接收一個(gè) ClassLoader parent 參數(shù)。這個(gè) parent 的目的就在于實(shí)現(xiàn)類加載的雙親委托。即: 某個(gè)類加載器在加載類時(shí),首先將加載任務(wù)委托給父類加載器,依次遞歸,如果父 類加載器可以完成類加載任務(wù),就成功返回;只有父類加載器無法完成此加載任務(wù)或者沒有父類加載器時(shí),才自己去加載。
1、避免重復(fù)加載,當(dāng)父加載器已經(jīng)加載了該類的時(shí)候,就沒有必要子ClassLoader再加載一次。 2、安全性考慮,防止核心API庫被隨意篡改。

因此我們自己創(chuàng)建的ClassLoader: new PathClassLoader("/sdcard/xx.dex", getClassLoader()); 并不僅僅只能加載 xx.dex中的class。
值得注意的是: c = findBootstrapClassOrNull(name); 按照方法名理解,應(yīng)該是當(dāng)parent為null時(shí)候,也能夠加載 BootClassLoader 加載的類。 newPathClassLoader("/sdcard/xx.dex", null) ,能否加載Activity.class? 但是實(shí)際上,Android當(dāng)中的實(shí)現(xiàn)為:(Java不同)



類加載


熱修復(fù)


PathClassLoader 中存在一個(gè)Element數(shù)組,Element類中存在一個(gè)dexFile成員表示dex文件,即:APK中有X個(gè)dex,則Element數(shù)組就有X個(gè)元素。
在 PathClassLoader 中的Element數(shù)組為:[patch.dex , classes.dex , classes2.dex]。如果存在Key.class位于patch.dex與classes2.dex中都存在一份,當(dāng)進(jìn)行類查找時(shí),循環(huán)獲得 dexElements 中的DexFile,查找到了Key.class則立即返回,不會(huì)再管后續(xù)的element中的DexFile是否能加載到Key.class了。
因此實(shí)際上,一種熱修復(fù)實(shí)現(xiàn)可以將出現(xiàn)Bug的class單獨(dú)的制作一份fix.dex文件(補(bǔ)丁包),然后在程序啟動(dòng)時(shí),從服務(wù)器下載fix.dex保存到某個(gè)路徑,再通過fix.dex的文件路徑,用其創(chuàng)建 Element 對(duì)象,然后將這個(gè) Element 對(duì)象插入到我們程序的類加載器 PathClassLoader 的 pathList 中的 dexElements 數(shù)組頭部。這樣在加載出現(xiàn)Bug的class時(shí)會(huì)優(yōu)先加載fix.dex中的修復(fù)類,從而解決Bug。

到此這篇關(guān)于Android虛擬機(jī)與類加載機(jī)制詳情的文章就介紹到這了,更多相關(guān)Android虛擬機(jī)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
安卓(Android)開發(fā)之統(tǒng)計(jì)App啟動(dòng)時(shí)間
當(dāng)大家要改善APP啟動(dòng)速度優(yōu)化的時(shí)候,首先要知道App的啟動(dòng)時(shí)間,那么改如何統(tǒng)計(jì)時(shí)間呢,下面我們一起來看看。2016-08-08
Android自定義ImageView實(shí)現(xiàn)自動(dòng)放大縮小動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Android自定義ImageView實(shí)現(xiàn)自動(dòng)放大縮小動(dòng)畫,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Android實(shí)現(xiàn)讀取SD卡下所有TXT文件名并用listView顯示出來的方法
這篇文章主要介紹了Android實(shí)現(xiàn)讀取SD卡下所有TXT文件名并用listView顯示出來的方法,涉及Android針對(duì)SD卡的讀取及文件遍歷等相關(guān)操作技巧,需要的朋友可以參考下2017-06-06
Android 系統(tǒng)實(shí)現(xiàn)多種開機(jī)動(dòng)畫和logo切換功能
這篇文章主要介紹了android 系統(tǒng)實(shí)現(xiàn)多種開機(jī)動(dòng)畫和logo切換功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-12-12
Android實(shí)現(xiàn)SQLite添加、更新及刪除行的方法
這篇文章主要介紹了Android實(shí)現(xiàn)SQLite添加、更新及刪除行的方法,涉及Android基于SQLiteDatabase類操作SQLite數(shù)據(jù)庫的基本技巧,需要的朋友可以參考下2016-08-08
Android?Banner本地和網(wǎng)絡(luò)輪播圖使用介紹
大家好,本篇文章講的是Android?Banner本地和網(wǎng)絡(luò)輪播圖使用介紹,感興趣的同學(xué)趕快來看一看吧,希望本篇文章對(duì)你起到幫助2021-11-11
flutter開發(fā)的app項(xiàng)目?打包成web
如果你的Flutter版本低于2.0,請(qǐng)先升級(jí)Flutter版本,創(chuàng)建一個(gè)web文件夾來存放web相關(guān)的資源,使用HTML渲染器打包,該渲染器提供的打開速度最快,并且具有良好的瀏覽器兼容性,使用默認(rèn)設(shè)置進(jìn)行打包,提供的打開速度為一般,但依然保持良好的瀏覽器兼容性2024-08-08
Flutter將整個(gè)App變?yōu)榛疑暮唵螌?shí)現(xiàn)方法
Flutter?是?Google?開源的?UI?工具包,幫助開發(fā)者通過一套代碼庫高效構(gòu)建多平臺(tái)精美應(yīng)用,這篇文章主要給大家介紹了關(guān)于Flutter將整個(gè)App變?yōu)榛疑膶?shí)現(xiàn)方法,在Flutter中實(shí)現(xiàn)整個(gè)App變?yōu)榛疑欠浅:唵蔚?需要的朋友可以參考下2021-12-12

