Android虛擬機與類加載機制詳情
JVM與Dalvik
Android應(yīng)用程序運行在Dalvik/ART虛擬機,并且每一個應(yīng)用程序?qū)?yīng)有一個單獨的Dalvik虛擬機實例。Dalvik虛擬機實則也算是一個Java虛擬機,只不過它執(zhí)行的不是class文件,而是dex文件。 Dalvik虛擬機與Java虛擬機共享有差不多的特性,差別在于兩者執(zhí)行的指令集是不一樣的,前者的指令集是基本寄存器的,而后者的指令集是基于堆棧的。
JMV基于棧,Dalvik基于寄存器
基于棧的虛擬機
對于基于棧的虛擬機來說,每一個運行時的線程,都有一個獨立的棧。棧中記錄了方法調(diào)用的歷史,每有一次方法調(diào)用,棧中便會多一個棧楨。最頂部的棧楨稱作當前棧楨,其代表著當前執(zhí)行的方法。基于棧的虛擬機通過操作數(shù)棧進行所有操作。
字節(jié)碼指令
在Androidstudio中搜索ASMPlugin,可以直接用這個插件查看字節(jié)碼
執(zhí)行過程
基于寄存器的虛擬機
寄存器
寄存器是CPU的組成部分。寄存器是有限存貯容量的高速存貯部件,它們可用來暫存指令、數(shù)據(jù)和位址。
基于寄存器的虛擬機
基于寄存器的虛擬機中沒有操作數(shù)棧,但是有很多虛擬寄存器。其實和操作數(shù)棧相同,這些寄存器也存放在運行時棧中,本質(zhì)上就是一個數(shù)組。與JVM相似,在Dalvik VM中每個線程都有自己的PC和調(diào)用棧,方法調(diào)用的活動記錄以幀為單位保存在調(diào)用棧上。
與JVM版相比,可以發(fā)現(xiàn)Dalvik版程序的指令數(shù)明顯減少了,數(shù)據(jù)移動次數(shù)也明顯減少了。
ART與Dalvik
Dalvik虛擬機執(zhí)行的是dex字節(jié)碼,解釋執(zhí)行。從Android 2.2版本開始,支持JIT及時編譯(Just In Time)在程序運行的過程中進行選擇熱點代碼(經(jīng)常執(zhí)行的代碼)進行編譯或者優(yōu)化。 而ART(Android Runtime) 是在 Android 4.4 中引入的一個開發(fā)者選項,也是 Android 5.0 及更高版本的默認 Android 運行時。ART虛擬機執(zhí)行的是本地機器碼。Android的運行時從Dalvik虛擬機替換成ART虛擬機,并不要求開發(fā)者將自己的應(yīng)用直接編譯成目標機器碼,APK仍然是一個包含dex字節(jié)碼的文件。那么,ART虛擬機執(zhí)行的本地機器碼是從哪里來?
dex2aot
Dalvik下應(yīng)用在安裝的過程,會執(zhí)行一次優(yōu)化,將dex字節(jié)碼進行優(yōu)化生成odex文件。而Art下將應(yīng)用的dex字節(jié)碼翻譯成本地機器碼的最恰當AOT時機也就發(fā)生在應(yīng)用安裝的時候。ART 引入了預(yù)先編譯機制(Ahead Of Time),在安裝時,ART 使用設(shè)備自帶的 dex2oat 工具來編譯應(yīng)用,dex中的字節(jié)碼將被編譯成本地機器碼。
odex的目的:預(yù)先提取,減少RAM的占用,因為沒有odex的話,系統(tǒng)要從apk包中提取dex再運行。
dexopt與dexaot
- dexopt:在Dalvik中虛擬機在加載一個dex文件時,對 dex 文件 進行 驗證 和 優(yōu)化的操作,其對 dex 文件的優(yōu)化結(jié)果變成了 odex(Optimized dex) 文件,這個文件和 dex 文件很像,只是使用了一些優(yōu)化操作碼。
- dex2oat:ART 預(yù)先編譯機制,在安裝時對 dex 文件執(zhí)行AOT 提前編譯操作,編譯為OAT(實際上是ELF文件)可執(zhí)行文件(機器碼)。
Android N的運作方式
ART 使用預(yù)先 (AOT) 編譯,并且從 Android N混合使用AOT編譯,解釋和JIT。 1、最初安裝應(yīng)用時不進行任何 AOT 編譯(安裝又快了),運行過程中解釋執(zhí)行,對經(jīng)常執(zhí)行的方法進行JIT,經(jīng)過 JIT 編譯的方法將會記錄到Profile配置文件中。 2、當設(shè)備閑置和充電時,編譯守護進程會運行,根據(jù)Profile文件對常用代碼進行 AOT 編譯。待下次運行時直接使用。
ClassLoader
介紹
任何一個 Java 程序都是由一個或多個 class 文件組成,在程序運行時,需要將 class 文件加載到 JVM 中才可以使用,負責加載這些 class 文件的就是 Java 的類加載機制。ClassLoader 的作用簡單來說就是加載 class 文件,提供給程序運行時使用。每個 Class 對象的內(nèi)部都有一個 classLoader 字段來標識自己是由哪個ClassLoader 加載的。
ClassLoader是一個抽象類,而它的具體實現(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,其實這說的應(yīng)該是在dalvik虛擬機上。但現(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加載流程與雙親委托機制
可以看到創(chuàng)建 ClassLoader 需要接收一個 ClassLoader parent 參數(shù)。這個 parent 的目的就在于實現(xiàn)類加載的雙親委托。即: 某個類加載器在加載類時,首先將加載任務(wù)委托給父類加載器,依次遞歸,如果父 類加載器可以完成類加載任務(wù),就成功返回;只有父類加載器無法完成此加載任務(wù)或者沒有父類加載器時,才自己去加載。
1、避免重復(fù)加載,當父加載器已經(jīng)加載了該類的時候,就沒有必要子ClassLoader再加載一次。 2、安全性考慮,防止核心API庫被隨意篡改。
因此我們自己創(chuàng)建的ClassLoader: new PathClassLoader("/sdcard/xx.dex", getClassLoader()); 并不僅僅只能加載 xx.dex中的class。
值得注意的是: c = findBootstrapClassOrNull(name); 按照方法名理解,應(yīng)該是當parent為null時候,也能夠加載 BootClassLoader 加載的類。 newPathClassLoader("/sdcard/xx.dex", null) ,能否加載Activity.class? 但是實際上,Android當中的實現(xiàn)為:(Java不同)
類加載
熱修復(fù)
PathClassLoader 中存在一個Element數(shù)組,Element類中存在一個dexFile成員表示dex文件,即:APK中有X個dex,則Element數(shù)組就有X個元素。
在 PathClassLoader 中的Element數(shù)組為:[patch.dex , classes.dex , classes2.dex]。如果存在Key.class位于patch.dex與classes2.dex中都存在一份,當進行類查找時,循環(huán)獲得 dexElements 中的DexFile,查找到了Key.class則立即返回,不會再管后續(xù)的element中的DexFile是否能加載到Key.class了。
因此實際上,一種熱修復(fù)實現(xiàn)可以將出現(xiàn)Bug的class單獨的制作一份fix.dex文件(補丁包),然后在程序啟動時,從服務(wù)器下載fix.dex保存到某個路徑,再通過fix.dex的文件路徑,用其創(chuàng)建 Element 對象,然后將這個 Element 對象插入到我們程序的類加載器 PathClassLoader 的 pathList 中的 dexElements 數(shù)組頭部。這樣在加載出現(xiàn)Bug的class時會優(yōu)先加載fix.dex中的修復(fù)類,從而解決Bug。
到此這篇關(guān)于Android虛擬機與類加載機制詳情的文章就介紹到這了,更多相關(guān)Android虛擬機內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android添加用戶組及自定義App權(quán)限的方法
今天小編就為大家分享一篇Android添加用戶組及自定義App權(quán)限的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07關(guān)于android studio通過命令行運行g(shù)radle編譯命令的問題
這篇文章主要介紹了關(guān)于android studio通過命令行運行g(shù)radle編譯命令的問題,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-11-11Android?Camera實現(xiàn)旋轉(zhuǎn)角度
這篇文章主要為大家詳細介紹了Android?Camera實現(xiàn)旋轉(zhuǎn)角度,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07Android實現(xiàn)Activity界面切換添加動畫特效的方法
這篇文章主要介紹了Android實現(xiàn)Activity界面切換添加動畫特效的方法,非常實用的技巧,需要的朋友可以參考下2014-08-08Android Studio實現(xiàn)華為手機的充電動畫效果
本篇文章介紹了我參照華為手機的充電動畫來仿照實現(xiàn)的樣例,這個動畫并不難實現(xiàn),不過案例精簡具有參考意義,需要的朋友快往下看吧2021-10-10Android 按后退鍵退出Android程序的實現(xiàn)方法
本篇文章介紹了,在Android中按后退鍵退出Android程序的實現(xiàn)方法。需要的朋友參考下2013-04-04Android Activity啟動模式之singleTop實例詳解
這篇文章主要介紹了Android Activity啟動模式之singleTop,結(jié)合實例形式較為詳細的分析了singleTop模式的功能、使用方法與相關(guān)注意事項,需要的朋友可以參考下2016-01-01Android應(yīng)用圖標在狀態(tài)欄上顯示實現(xiàn)原理
Android應(yīng)用圖標在狀態(tài)欄上顯示,以及顯示不同的圖標,其實很研究完后,才發(fā)現(xiàn),很簡單,具體實現(xiàn)如下,感興趣的朋友可以參考下哈2013-06-06