java虚拟机与安卓虚拟机的区别
目录
整体区分
Dailk和ART
安卓中的类加载器
类加载机制采用双亲委托机制
整体区分
JVM是基于栈的虚拟机;而安卓是基于寄存器的虚拟机(ART和davik)。
1、寄存器
上边这个a+b在寄存器中的运行方式是:从物理地址为100的位置拿到第一个数放到寄存器AX中,物理地址是104的地方拿到第二个数存到BX中,,然后再ALU里边完成算数相加,将结果存到寄存器CX中,最后将结果地址存在108的位置。寄存器就是一个晶体管。安卓的虚拟机是为了模拟真实的寄存器的操作流程。
相比于JVM。每次都需要将要操作的数据经过操作数栈,安卓这种基于寄存器的方式指令数量明显会减少很多。
同样一个1+2的操作。在JVM里边会是这样的:
安卓上边只有4条指令,而JVM则有多达8条指令。
基于寄存器的虚拟机开发难度相比基于栈的更高。
Dailk和ART
那么,ART虚拟机执行的本地机器码是从哪里来?
安卓中的类加载器
类加载是一个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虚拟机与安卓虚拟机的区别相关推荐
- 安卓虚拟机_安卓虚拟机(*New*)v1.1.31去广告/去推荐/Mod/精简/VIP版
软件简介: VMOS(虚拟大师)是一款以Virtual Machine(简称VM,即虚拟机)技术为主的APP(安卓应用)软件.通过VM技术,把开源的安卓系统(支持任意版本),无需root权限,以普通应 ...
- 安卓虚拟机_安卓虚拟机雷电模拟器
点击上方蓝字关注我们! 各位小狐,大家晚上好啊! 前不久,收到了一个小狐的私信,问我们有没有PC端的Android虚拟机可以使用,我们这边找了一些比较受欢迎的,查找了一些资源,目前安装简单,效果经过小 ...
- dalvik虚拟机与Java区别_05 Android---java虚拟机跟dalvik虚拟机的区别(从01开始点点入门,视频+笔记)...
大家好,我是森森 这节课我简单给大家介绍一下java虚拟机跟安卓系统虚拟机的区别.可能时间太晚了,有点不在状态,也有点紧张,大家见谅. 05java虚拟机跟dalvik虚拟机的区别 这篇文章重点写一写 ...
- 安卓Java虚拟机大小_虚拟机为安卓流畅度背锅,是因为关系数十万程序员饭碗?...
导读:虚拟机相当于应用程序在不同运行环境中的翻译. 说起谷歌安卓系统的"虚拟机",很多人爱拿它和苹果iOS做比较,结果,安卓的很多短腿儿都让虚拟机背了锅,比如安卓手机运存容量是iP ...
- Java虚拟机和Dalvik虚拟机的区别
java虚拟机和Dalvik虚拟机的区别 该文章是本人转载的,觉得写的不错,和大家分享一下 Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvi ...
- (Android)java虚拟机和Dalvik虚拟机的区别
Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvik虚拟机也第一次进入了人们的视野.它对内存的高效使用,和在低速CPU上表现出的高性能,确实令 ...
- java dalvik_Java虚拟机和Dalvik虚拟机的区别
java虚拟机和Dalvik虚拟机的区别: java虚拟机 Dalvik虚拟机 java虚拟机基于栈. 基于栈的机器必须使用指令来载入和操作栈上数据,所需指令更多更多 dalvik虚拟机是基于寄存器的 ...
- 【Android 安装包优化】APK 打包流程 ( 文件结构 | 打包流程 | 安装流程 | 安卓虚拟机 )
文章目录 一.APK 文件结构 二.APK 打包流程 三.APK 安装流程 四.安卓虚拟机 一.APK 文件结构 Android 应用的安装包时 以 " .apk " 为后缀的 A ...
- android -------- java虚拟机和Dalvik虚拟机
2019独角兽企业重金招聘Python工程师标准>>> java虚拟机 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机有自己完善的硬体 ...
- java中判断undefined_Java虚拟机系列一:一文搞懂 JVM 架构和运行时数据区
前言 之前写博客一直比较随性,主题也很随意,就是想到什么写什么,对什么感兴趣就写什么.虽然写起来无拘无束,自在随意,但也带来了一些问题,每次写完一篇后就要去纠结下一篇到底写什么,看来选择太多也不是好事 ...
最新文章
- 一个可以卷起来的蓝牙键盘,简直是办公码字神器!
- 标准情况下的最优方案与魔鬼赛道
- JAVA并发编程JUC基础学习(简介)
- 【SD】交货单如何在保存时更改LIKP表的值?
- MySQL高级 - 应用优化
- 如何在Marketing Cloud的弹出UI窗口里添加扩展字段
- outlook附件大小限制_如何在Outlook中调整大图片附件的大小
- android 论坛_如何看待百度android吧萎靡现象与吧主的无所作为
- asp多表查询并显示_MySQL多表查询与事务
- css绘制卡券优惠券_使用css创建一个优惠券的方法
- 计算机显卡(GPU)基础介绍
- CSS | 如何达到监听页面滚动的效果?
- 废柴日记7:迟到的『构造最小生成树算法』④
- 《Android源码设计模式解析与实战》读书笔记(十七)
- 数据结构基础(严蔚敏)
- VBA 类模块理解和使用总结
- 【IT运维小知识】安全组是什么意思?
- 虚拟机向主机复制文件中断产生的不合理临时文件【win磁盘空间不足解决方法】
- 管理者应该掌握的八项基本技能
- pycharm Failed to connect to github.com port 443: Timed out
热门文章
- 太全面了!Python 编程的最好搭档—VSCode 实用指南!
- 又五年后回头再看我的程序员生涯
- 【Matlab三维路径规划】蚁群算法三维路径规划【含源码 179期】
- 启用计算机的快捷键,电脑启动热键对照表
- uni-app 分享给好友,生成小程序二维码海报
- 深入学习 esp8266 wifimanager源码解析(打造专属自己的web配网)(最全的wifimanager介绍))
- mate桌面暗色调超好看的配置
- 关于高速光耦6n137的使用总结_高速光耦6n137典型应用电路图汇总(多谐振荡/光电隔离器/光耦开关) - 全文...
- C#数据Encrypt加密Encrypt解密的算法使用
- 多维度对抗 Windows AppLocker