日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Android虛擬機與類加載機制詳情_Android

作者:havenobug??????? ? 更新時間: 2022-10-31 編程語言

JVM與Dalvik

Android應用程序運行在Dalvik/ART虛擬機,并且每一個應用程序對應有一個單獨的Dalvik虛擬機實例。Dalvik虛擬機實則也算是一個Java虛擬機,只不過它執行的不是class文件,而是dex文件。 Dalvik虛擬機與Java虛擬機共享有差不多的特性,差別在于兩者執行的指令集是不一樣的,前者的指令集是基本寄存器的,而后者的指令集是基于堆棧的。?

?JMV基于棧,Dalvik基于寄存器

基于棧的虛擬機

對于基于棧的虛擬機來說,每一個運行時的線程,都有一個獨立的棧。棧中記錄了方法調用的歷史,每有一次方法調用,棧中便會多一個棧楨。最頂部的棧楨稱作當前棧楨,其代表著當前執行的方法。基于棧的虛擬機通過操作數棧進行所有操作。?

字節碼指令

在Androidstudio中搜索ASMPlugin,可以直接用這個插件查看字節碼?

執行過程

基于寄存器的虛擬機

寄存器

寄存器是CPU的組成部分。寄存器是有限存貯容量的高速存貯部件,它們可用來暫存指令、數據和位址。?

基于寄存器的虛擬機

基于寄存器的虛擬機中沒有操作數棧,但是有很多虛擬寄存器。其實和操作數棧相同,這些寄存器也存放在運行時棧中,本質上就是一個數組。與JVM相似,在Dalvik VM中每個線程都有自己的PC和調用棧,方法調用的活動記錄以幀為單位保存在調用棧上。?

?與JVM版相比,可以發現Dalvik版程序的指令數明顯減少了,數據移動次數也明顯減少了。

ART與Dalvik

Dalvik虛擬機執行的是dex字節碼,解釋執行。從Android 2.2版本開始,支持JIT及時編譯(Just In Time)在程序運行的過程中進行選擇熱點代碼(經常執行的代碼)進行編譯或者優化。 而ART(Android Runtime) 是在 Android 4.4 中引入的一個開發者選項,也是 Android 5.0 及更高版本的默認 Android 運行時。ART虛擬機執行的是本地機器碼。Android的運行時從Dalvik虛擬機替換成ART虛擬機,并不要求開發者將自己的應用直接編譯成目標機器碼,APK仍然是一個包含dex字節碼的文件。那么,ART虛擬機執行的本地機器碼是從哪里來?

dex2aot

Dalvik下應用在安裝的過程,會執行一次優化,將dex字節碼進行優化生成odex文件。而Art下將應用的dex字節碼翻譯成本地機器碼的最恰當AOT時機也就發生在應用安裝的時候。ART 引入了預先編譯機制(Ahead Of Time),在安裝時,ART 使用設備自帶的 dex2oat 工具來編譯應用,dex中的字節碼將被編譯成本地機器碼。?

?odex的目的:預先提取,減少RAM的占用,因為沒有odex的話,系統要從apk包中提取dex再運行。

dexopt與dexaot

  • dexopt:Dalvik中虛擬機在加載一個dex文件時,對 dex 文件 進行 驗證 和 優化的操作,其對 dex 文件的優化結果變成了 odex(Optimized dex) 文件,這個文件和 dex 文件很像,只是使用了一些優化操作碼。
  • dex2oat:ART 預先編譯機制,在安裝時對 dex 文件執行AOT 提前編譯操作,編譯為OAT(實際上是ELF文件)可執行文件(機器碼)。

Android N的運作方式

ART 使用預先 (AOT) 編譯,并且從 Android N混合使用AOT編譯,解釋和JIT。 1、最初安裝應用時不進行任何 AOT 編譯(安裝又快了),運行過程中解釋執行,對經常執行的方法進行JIT,經過 JIT 編譯的方法將會記錄到Profile配置文件中。 2、當設備閑置和充電時,編譯守護進程會運行,根據Profile文件對常用代碼進行 AOT 編譯。待下次運行時直接使用。?

ClassLoader

介紹

任何一個 Java 程序都是由一個或多個 class 文件組成,在程序運行時,需要將 class 文件加載到 JVM 中才可以使用,負責加載這些 class 文件的就是 Java 的類加載機制。ClassLoader 的作用簡單來說就是加載 class 文件,提供給程序運行時使用。每個 Class 對象的內部都有一個 classLoader 字段來標識自己是由哪個ClassLoader 加載的。?

?ClassLoader是一個抽象類,而它的具體實現類主要有:

  • BootClassLoader:用于加載Android Framework層class文件。
  • PathClassLoader:用于Android應用程序類加載器。可以加載指定的dex,以及jar、zip、apk中的classes.dex
  • DexClassLoader:用于加載指定的dex,以及jar、zip、apk中的classes.dex

很多博客里說PathClassLoader只能加載已安裝的apk的dex,其實這說的應該是在dalvik虛擬機上。但現在一般不用關心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加載流程與雙親委托機制

可以看到創建 ClassLoader 需要接收一個 ClassLoader parent 參數。這個 parent 的目的就在于實現類加載的雙親委托。即: 某個類加載器在加載類時,首先將加載任務委托給父類加載器,依次遞歸,如果父 類加載器可以完成類加載任務,就成功返回;只有父類加載器無法完成此加載任務或者沒有父類加載器時,才自己去加載。

1、避免重復加載,當父加載器已經加載了該類的時候,就沒有必要子ClassLoader再加載一次。 2、安全性考慮,防止核心API庫被隨意篡改。?

因此我們自己創建的ClassLoader: new PathClassLoader("/sdcard/xx.dex", getClassLoader()); 并不僅僅只能加載 xx.dex中的class。

值得注意的是: c = findBootstrapClassOrNull(name); 按照方法名理解,應該是當parent為null時候,也能夠加載 BootClassLoader 加載的類。 newPathClassLoader("/sdcard/xx.dex", null) ,能否加載Activity.class? 但是實際上,Android當中的實現為:(Java不同)

類加載

熱修復

?PathClassLoader 中存在一個Element數組,Element類中存在一個dexFile成員表示dex文件,即:APK中有X個dex,則Element數組就有X個元素。

在 PathClassLoader 中的Element數組為:[patch.dex , classes.dex , classes2.dex]。如果存在Key.class位于patch.dex與classes2.dex中都存在一份,當進行類查找時,循環獲得 dexElements 中的DexFile,查找到了Key.class則立即返回,不會再管后續的element中的DexFile是否能加載到Key.class了。

因此實際上,一種熱修復實現可以將出現Bug的class單獨的制作一份fix.dex文件(補丁包),然后在程序啟動時,從服務器下載fix.dex保存到某個路徑,再通過fix.dex的文件路徑,用其創建 Element 對象,然后將這個 Element 對象插入到我們程序的類加載器 PathClassLoader 的 pathList 中的 dexElements 數組頭部。這樣在加載出現Bug的class時會優先加載fix.dex中的修復類,從而解決Bug。?

原文鏈接:https://juejin.cn/post/7139541557245378568

欄目分類
最近更新