Android虚拟机与类加载机制详情

目录
  • JVM与Dalvik
  • 基于栈的虚拟机
  • 字节码指令
    • 执行过程
  • 基于寄存器的虚拟机
    • 寄存器
    • 基于寄存器的虚拟机
  • ART与Dalvik
  • dex2aot
    • dexopt与dexaot
  • Android N的运作方式
  • ClassLoader
    • 介绍
    • ClassLoader加载流程与双亲委托机制
    • 类加载
  • 热修复

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。

到此这篇关于Android虚拟机与类加载机制详情的文章就介绍到这了,更多相关Android虚拟机内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • android 使用虚拟机安装apk(图文教程)

    1.启动虚拟机 2.我的android sdk在"E:\android\android开发环境\android SDK\platform-tools"把要安装的apk复制到这个根目录(和adb.exe同文件夹). 2.点击电脑左下角的"开始"按钮,输入cmd然后点击回车打开cmd输入框. 3. (由于我的Android SDK安装路径为e盘,所以需要定位模拟器platform-tools目录) 在cmd命令提示符中输入E: 回车,如图 第一行, 4.apk名称为zq

  • 详解Android类加载ClassLoader

    基本知识 Java的类加载设计了一套双亲代理的模式,使得用户没法替换系统的核心类,从而让应用更安全.所谓双亲代理就是指,当加载类的时候首先去Bootstrap中加载类,如果没有则去Extension中加载,如果再没有才去AppClassLoader中去加载.从而实现安全和稳定. Java ClassLoader BootstrapClassLoader 引导类加载器 ,用来加载Java的核心库.通过底层代码来实现的,基本上只要parent为null,那就表示引导类加载器. 比如:charsets

  • Android APK文件在电脑(PC虚拟机)上面运行方法

    APK是Android系统的发布的工程包,很多时候我们想在电脑上而非Android手机上面运行它.下面就提供下Android APK文件在电脑上面运行方法. 首先要配置android环境变量,如果配置好了,安装就会很方便了. 可以在系统变量的path下追加,也可以在用户变量的path下追加,区别应该都知道的. 追加时不要忘了先用英文分号";"分隔前后环境变量值.添加android环境变量的值时要注意,adb.exe已经从tools目录转移到platform-tools目录了,具体可以看

  • Android 虚拟机中的内存分配与OOM问题详解

    目录 背景知识 一.Android VM的内存空间 1.查看内存的API 二.Android VM内存分配流程 小结 三.出现OOM的建议解决方案 背景知识 Android中每个App默认情况下是运行在一个独立进程中的, 而这个独立进程正是从Zygote孵化出来的VM进程, 也就是说, 也就是说每个Android APP在运行时会启动一个Java虚拟机. 并且系统会给它分配固定的内存空间(手机厂商会根据手机的配置情况来对其进行调整). 一.Android VM的内存空间 Android是一个多任

  • Android编程图片加载类ImageLoader定义与用法实例分析

    本文实例讲述了Android编程图片加载类ImageLoader定义与用法.分享给大家供大家参考,具体如下: 解析: 1)图片加载使用单例模式,避免多次调用时产生死锁 2)核心对象 LruCache 图片加载时先判断缓存里是否有图片,如果有,就使用缓存里的 没有就加载网络的,然后置入缓存 3)使用了线程池ExecutorService mThreadPool技术 4)使用了Semaphore 信号来控制变量按照先后顺序执行,避免空指针的问题 如何使用: 在Adapter里加载图片时 复制代码 代

  • vmware虚拟机安装安卓Android x86的方法步骤

    有时候只是想测试一个app,又不想在手机上做个测试,这个时候我们就可以用虚拟机来完成这件事情.首先到官网上去下载一个安卓系统(https://www.android-x86.org/),我这里用:android-x86-9.0-rc1.iso做演示. 或者选择本地安卓系统下载地址:https://www.jb51.net/softs/203311.html 在提供一个VMware15的下载地址:https://www.jb51.net/softs/638385.html VMware15 for

  • AndroidStudio中AVD虚拟机设备空间不足调试过程出现的黑屏问题及解决方案

    AVD出现空间不足时,会造成一些功能没有完全呈现出来,给开发人员调试会出现一个很大的问题,不能直观地看到调试的结果. 所以,必须将AVD的存储空间配置好,才能够保证开发过程少出错误. 下面找路径 C:\Users\Administrator\.android\avd\ 说明: 路径一般为.android默认的路径,比如我的就是C:\Users\Administrator\.android\avdavd目录下,放的是你已经创建的虚拟机设备,比如我现在要修改设备空间的是AVD.avd 就可以直接进入

  • unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk)

    unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk),总的流程分为以下6个步骤: 1.安装java_jdk 2.配置java环境变量 3.更新android的sdk 4.从Unity3d中发布出apk文件 5.创建android虚拟机并运行 6.将apk文件安装到android虚拟机中 (为方便新手,在下面对每个步骤的具体操作及可能遇到的问题详细提一下) 1.安装java_jdk 官网(www.java.com),免费,我安装的文件的名字是j

  • Android studio虚拟机在启动界面和桌面出现画面模糊花屏问题的解决方法

    1.之前自己的虚拟机这样设置没问题,今天突然出现这样的花屏 2.最后解决了,解决方法,按照下边红框设置 3.问题方法说明: 之前看不太明白,就找的翻译 反思:之前是设置的自动(默认是硬件渲染)可以,今天突然出现花屏那样的问题,搜遍全网没找到方法,最后有个大佬指点按照上边的方法设置(软件渲染)配置虚拟机,解决. 可能自己电脑硬件图形卡(不知道什么东东)哪里出了问题,也可能不小心更新组件后,android studio的设置出问题啦. 总结 到此这篇关于Android studio虚拟机在启动界面和

  • 解决android关于打开虚拟机时右侧工具栏不显示的问题

    一开始我就纳闷了,怎么调试都只是一个光溜溜的界面,右侧的工具栏都没有 如图: 就一个光秃秃的界面,什么都没有,这就对调试很不方便 于是我就试了试各种方法,然而并没有什么卵用. 后来一次无意之后发现我好像皮肤没选中即: 这就是问题的关键所在,当你没有选择的皮肤为no skin时,它的工具栏就不会出来 所以解决办法是: 将皮肤随便选一个就行了,但就是不能选no skin 以上这篇解决android关于打开虚拟机时右侧工具栏不显示的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多

随机推荐