目录

整体区分

Dailk和ART

安卓中的类加载器

类加载机制采用双亲委托机制



整体区分

JVM是基于栈的虚拟机;而安卓是基于寄存器的虚拟机(ART和davik)。

1、寄存器

上边这个a+b在寄存器中的运行方式是:从物理地址为100的位置拿到第一个数放到寄存器AX中,物理地址是104的地方拿到第二个数存到BX中,,然后再ALU里边完成算数相加,将结果存到寄存器CX中,最后将结果地址存在108的位置。寄存器就是一个晶体管。安卓的虚拟机是为了模拟真实的寄存器的操作流程。

        基于寄存器的虚拟机中没有操作数栈,但是有很多虚拟寄存器。其实和操作数栈相同,这些寄存器也存放 在运行时栈中,本质上就是一个数组。与JVM相似,在Dalvik VM中每个线程都有自己的PC和调用栈,方法 调用的活动记录以帧为单位保存在调用栈上。

相比于JVM。每次都需要将要操作的数据经过操作数栈,安卓这种基于寄存器的方式指令数量明显会减少很多。

同样一个1+2的操作。在JVM里边会是这样的:

安卓上边只有4条指令,而JVM则有多达8条指令。

基于寄存器的虚拟机开发难度相比基于栈的更高。

Dailk和ART

        DVM也是实现了JVM规范的一个虚拟器,默认使用CMS垃圾回收器,但是与JVM运行 Class 字节码不同,DVM 执行 Dex(Dalvik Executable Format)** ——专为 Dalvik 设计的一种压缩格式。Dex 文件是很多 .class 文件处理压 缩后的产物,最终可以在 Android 运行时环境执行。
        而ARTAndroid Runtime 是在 Android 4.4 中引入的一个开发者选项,也是 Android 5.0 及更高版本的默认 Android 运行时。ART 和 Dalvik 都是运行 Dex 字节码的兼容运行时,因此针对 Dalvik 开发的应用也能在 ART 环 境中运作。
dexoptdexaot
dexopt
        在Dalvik中虚拟机在加载一个dex文件时,对 dex 文件 进行 验证 和 优化的操作,其对 dex 文件的优化结果变成了 odex(Optimized dex) 文件,这个文件和 dex 文件很像,只是使用了一些优化操作码。
dex2oat
        ART 预先编译机制,在安装时对 dex 文件执行AOT 提前编译操作,编译为OAT(实际上是ELF文件)可执行 文件(机器码)
        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虚拟机执行的本地机器码是从哪里来?

        Dalvik下应用在安装的过程,会执行一次优化,将dex字节码进行优化生成odex文件。而Art下将应用的dex字 节码翻译成本地机器码的最恰当AOT(Ahead Of Time)时机也就发生在应用安装的时候。ART 引入了 ,在安装时,ART 使用设备自带的 dex2oat 工具来编译应用,dex中的字节码将被编译成本地机器码。
AndroidN的运行方式
ART使用预先(AOT)编译,并且从AndroidN混合使用AOT编译,解释和JIT。
1、最初安装应用时不进行任何AOT编译(安装又快了),运行过程中解释执行,对经常执行的方法进行JIT(其实就是记录的一些类的信息),经过JIT(JIT编译的代码只有本次有效)编译的方法将会记录到Profile配置文件中。
2、当设备闲置和充电时,编译守护进程会运行,根据Profile文件对常用代码进行AOT编译。待下次运行时直接使用。
Dalvik的dex就是dex文件,而ART的odex,已经是机器码了。

安卓中的类加载器

类加载是一个IO操作,所以这里必须要用缓存。加载类还需要解析出来,将类的信息保存到方法区。

类加载机制采用双亲委托机制

有两个好处:一个避免多次加载;而是安全,防止核心类被篡改(如果改掉了系统的核心代码,这可能导致后续出现了不可预测的错误)。

例如我们自定义String类:

所有用到了equals方法的地方都会崩溃!甚至连系统流程都可能被影响。

Android类加载流程

安卓中主要有三个类加载器:BootClassLoader,DexClassLoader, PathClassLoader,第一个用来加载Framework中的类,后两个用来加载自己写的类和谷歌的拓展库,例如AppCompatActivity等,需要注意的是,在Android8之后,DexClassLoader, PathClassLoader已经没有区分了,我们在加载类的时候,用的还是PathClassLoader,之所以还保留DexClassLoader,谷歌可能是考虑的拓展原因。

安卓类加载的流程:

// dalvik.system.BaseDexClassLoader#findClass
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {// First, check whether the class is present in our shared libraries.if (sharedLibraryLoaders != null) {for (ClassLoader loader : sharedLibraryLoaders) {try {return loader.loadClass(name);} catch (ClassNotFoundException ignored) {}}}// Check whether the class in question is present in the dexPath that// this classloader operates on.List<Throwable> suppressedExceptions = new ArrayList<Throwable>();// 从这里去加载真正的ClassClass c = pathList.findClass(name, suppressedExceptions);if (c == null) {ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);for (Throwable t : suppressedExceptions) {cnfe.addSuppressed(t);}throw cnfe;}return c;
}

上边的一个关键变量:pathList,其实是DexPathList。DexPathList实在BaseClassLoader的构造方法中进行的初始化,并且将dex文件的路径传递到DexPathList中,这是为了后边的解析。

public BaseDexClassLoader(String dexPath,String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders,boolean isTrusted) {super(parent);// Setup shared libraries before creating the path list. ART relies on the class loader// hierarchy being finalized before loading dex files.this.sharedLibraryLoaders = sharedLibraryLoaders == null? null: Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);reportClassLoaderChain();
}

来看看DexPathList的构造方法:

public DexPathList(ClassLoader definingContext, String librarySearchPath) {if (definingContext == null) {throw new NullPointerException("definingContext == null");}this.definingContext = definingContext;this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);this.systemNativeLibraryDirectories =splitPaths(System.getProperty("java.library.path"), true);// splitDexPath,分组,虽然一般一个apk只有一个dex文件,但是我们是能够支持多个dex文件的同时解析的。传入的格式:/a/a/dex:/a/b.dex。两个dex文件中间用冒号隔开。this.nativeLibraryPathElements = makePathElements(getAllNativeLibraryDirectories());
}
// 一个dex生成一个element,多个dex就有多个element,所以这里使用数组。
private static Element[] makePathElements(List<File> files, File optimizedDirectory,List<IOException> suppressedExceptions) {return makeDexElements(files, optimizedDirectory, suppressedExceptions, null);
}

进入DexPathList的查找类的流程:

// dalvik.system.DexPathList#findClass
public Class<?> findClass(String name, List<Throwable> suppressed) {for (Element element : dexElements) {Class<?> clazz = element.findClass(name, definingContext, suppressed);if (clazz != null) {return clazz;}}if (dexElementsSuppressedExceptions != null) {suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));}return null;
}

接着会走到这里:

public Class<?> findClass(String name, ClassLoader definingContext,List<Throwable> suppressed) {return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed): null;
}

接着走到这里:

// DexFile里边:
private static native Class defineClassNative(String name, ClassLoader loader, Object cookie,DexFile dexFile)throws ClassNotFoundException, NoClassDefFoundError;

最终进入C++层:

// dalvik_system_DexFile.cppstatic jclass DexFile_defineClassNative(JNIEnv* env,jclass,jstring javaName,jobject javaLoader,jobject cookie,jobject dexFile) {std::vector<const DexFile*> dex_files;const OatFile* oat_file;if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) {VLOG(class_linker) << "Failed to find dex_file";DCHECK(env->ExceptionCheck());return nullptr;}ScopedUtfChars class_name(env, javaName);if (class_name.c_str() == nullptr) {VLOG(class_linker) << "Failed to find class_name";return nullptr;}const std::string descriptor(DotToDescriptor(class_name.c_str()));const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));for (auto& dex_file : dex_files) {const dex::ClassDef* dex_class_def =OatDexFile::FindClassDef(*dex_file, descriptor.c_str(), hash);if (dex_class_def != nullptr) {ScopedObjectAccess soa(env);ClassLinker* class_linker = Runtime::Current()->GetClassLinker();StackHandleScope<1> hs(soa.Self());Handle<mirror::ClassLoader> class_loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));ObjPtr<mirror::DexCache> dex_cache =class_linker->RegisterDexFile(*dex_file, class_loader.Get());if (dex_cache == nullptr) {// OOME or InternalError (dexFile already registered with a different class loader).soa.Self()->AssertPendingException();return nullptr;}ObjPtr<mirror::Class> result = class_linker->DefineClass(soa.Self(),descriptor.c_str(),hash,class_loader,*dex_file,*dex_class_def);// Add the used dex file. This only required for the DexFile.loadClass API since normal// class loaders already keep their dex files live.class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile),class_loader.Get());if (result != nullptr) {VLOG(class_linker) << "DexFile_defineClassNative returning " << result<< " for " << class_name.c_str();return soa.AddLocalReference<jclass>(result);}}}VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str();return nullptr;
}

整体流程:

直观图:

一定要注意,有几个dex文件,Element数组里边的元素就有几个。

热修复原理

(1)获取当前应用的PathClassLoader

(2)反射获取到DexPathList属性对象pathList;

(3)反射修改pathList的dexElemets

1、把补丁包的path.dex转化为Element[];(patch)

2、获得pathList的dexElements属性;(old)

3、合并patch+old,并反射赋值给pathList的dexElements;patch一定要放在前边

在安卓N之后,由于使用了ART, 常用的都会被编译成机器码,区分Dalvik,不会再去找dex文件,采用了AOT方式,PathClassLoader在创建之初就会将类加载进去,导致使用上边这种方式会失效。此时可以采用的方式是自定义ClassLoader反射替换掉PathClassLoader,修改其中的加载流程。Tinker就采用了这种方式。

参考文章

Android dex、odex、oat、vdex、art区别_慢慢的燃烧的博客-CSDN博客_odex vdex

Android[art]-Android dex,odex,oat,vdex,art文件结构学习总结_TaylorPotter的博客-CSDN博客_vdex文件

java虚拟机与安卓虚拟机的区别相关推荐

  1. 安卓虚拟机_安卓虚拟机(*New*)v1.1.31去广告/去推荐/Mod/精简/VIP版

    软件简介: VMOS(虚拟大师)是一款以Virtual Machine(简称VM,即虚拟机)技术为主的APP(安卓应用)软件.通过VM技术,把开源的安卓系统(支持任意版本),无需root权限,以普通应 ...

  2. 安卓虚拟机_安卓虚拟机雷电模拟器

    点击上方蓝字关注我们! 各位小狐,大家晚上好啊! 前不久,收到了一个小狐的私信,问我们有没有PC端的Android虚拟机可以使用,我们这边找了一些比较受欢迎的,查找了一些资源,目前安装简单,效果经过小 ...

  3. dalvik虚拟机与Java区别_05 Android---java虚拟机跟dalvik虚拟机的区别(从01开始点点入门,视频+笔记)...

    大家好,我是森森 这节课我简单给大家介绍一下java虚拟机跟安卓系统虚拟机的区别.可能时间太晚了,有点不在状态,也有点紧张,大家见谅. 05java虚拟机跟dalvik虚拟机的区别 这篇文章重点写一写 ...

  4. 安卓Java虚拟机大小_虚拟机为安卓流畅度背锅,是因为关系数十万程序员饭碗?...

    导读:虚拟机相当于应用程序在不同运行环境中的翻译. 说起谷歌安卓系统的"虚拟机",很多人爱拿它和苹果iOS做比较,结果,安卓的很多短腿儿都让虚拟机背了锅,比如安卓手机运存容量是iP ...

  5. Java虚拟机和Dalvik虚拟机的区别

    java虚拟机和Dalvik虚拟机的区别 该文章是本人转载的,觉得写的不错,和大家分享一下 Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvi ...

  6. (Android)java虚拟机和Dalvik虚拟机的区别

    Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvik虚拟机也第一次进入了人们的视野.它对内存的高效使用,和在低速CPU上表现出的高性能,确实令 ...

  7. java dalvik_Java虚拟机和Dalvik虚拟机的区别

    java虚拟机和Dalvik虚拟机的区别: java虚拟机 Dalvik虚拟机 java虚拟机基于栈. 基于栈的机器必须使用指令来载入和操作栈上数据,所需指令更多更多 dalvik虚拟机是基于寄存器的 ...

  8. 【Android 安装包优化】APK 打包流程 ( 文件结构 | 打包流程 | 安装流程 | 安卓虚拟机 )

    文章目录 一.APK 文件结构 二.APK 打包流程 三.APK 安装流程 四.安卓虚拟机 一.APK 文件结构 Android 应用的安装包时 以 " .apk " 为后缀的 A ...

  9. android -------- java虚拟机和Dalvik虚拟机

    2019独角兽企业重金招聘Python工程师标准>>> java虚拟机 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机有自己完善的硬体 ...

  10. java中判断undefined_Java虚拟机系列一:一文搞懂 JVM 架构和运行时数据区

    前言 之前写博客一直比较随性,主题也很随意,就是想到什么写什么,对什么感兴趣就写什么.虽然写起来无拘无束,自在随意,但也带来了一些问题,每次写完一篇后就要去纠结下一篇到底写什么,看来选择太多也不是好事 ...

最新文章

  1. 一个可以卷起来的蓝牙键盘,简直是办公码字神器!
  2. 标准情况下的最优方案与魔鬼赛道
  3. JAVA并发编程JUC基础学习(简介)
  4. 【SD】交货单如何在保存时更改LIKP表的值?
  5. MySQL高级 - 应用优化
  6. 如何在Marketing Cloud的弹出UI窗口里添加扩展字段
  7. outlook附件大小限制_如何在Outlook中调整大图片附件的大小
  8. android 论坛_如何看待百度android吧萎靡现象与吧主的无所作为
  9. asp多表查询并显示_MySQL多表查询与事务
  10. css绘制卡券优惠券_使用css创建一个优惠券的方法
  11. 计算机显卡(GPU)基础介绍
  12. CSS | 如何达到监听页面滚动的效果?
  13. 废柴日记7:迟到的『构造最小生成树算法』④
  14. 《Android源码设计模式解析与实战》读书笔记(十七)
  15. 数据结构基础(严蔚敏)
  16. VBA 类模块理解和使用总结
  17. 【IT运维小知识】安全组是什么意思?
  18. 虚拟机向主机复制文件中断产生的不合理临时文件【win磁盘空间不足解决方法】
  19. 管理者应该掌握的八项基本技能
  20. pycharm Failed to connect to github.com port 443: Timed out

热门文章

  1. 太全面了!Python 编程的最好搭档—VSCode 实用指南!
  2. 又五年后回头再看我的程序员生涯
  3. 【Matlab三维路径规划】蚁群算法三维路径规划【含源码 179期】
  4. 启用计算机的快捷键,电脑启动热键对照表
  5. uni-app 分享给好友,生成小程序二维码海报
  6. 深入学习 esp8266 wifimanager源码解析(打造专属自己的web配网)(最全的wifimanager介绍))
  7. mate桌面暗色调超好看的配置
  8. 关于高速光耦6n137的使用总结_高速光耦6n137典型应用电路图汇总(多谐振荡/光电隔离器/光耦开关) - 全文...
  9. C#数据Encrypt加密Encrypt解密的算法使用
  10. 多维度对抗 Windows AppLocker