| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> JVM 字节码文件与类加载 -> 正文阅读 |
|
[移动开发]JVM 字节码文件与类加载 |
文章目录该篇文章是建立在 JVM 运行时数据区(栈和堆) 、JVM GC 和 JVM Hotspot 虚拟机与 Dalvik&ART 虚拟机堆栈的区别 三篇文章的基础上讲解,所以在阅读前建议先理解看完上述文章,会对该篇文章的理解很有帮助。 在之前的篇章中对运行时数据区、执行引擎的 GC 都有详细的介绍和说明,该篇文章将会讲解执行引擎中的解释器、分析器以及类加载子系统相关的知识。 前端编译器与后端编译器我们都知道代码要运行起来,首先就会经过编译,例如将用 Java 语言编写的代码编译为 .class 文件,在 Android 中就是将代码编译为 .dex 文件,.dex 文件可以认为是多个 .class 文件的集合。将代码编译为字节码文件后,想要运行这些字节码文件同样的也需要编译器将字节码编译为机器码让系统可以识别。 也就是说,从编写代码到机器可识别,会经过两个编译器: 前端编译器和后端编译器的作用:
解释执行和 JIT&AOT
上图是 Android ART 虚拟机的执行引擎,执行引擎有解释器和 Android 的 JIT(Just In Time,即时编译器),还有 AOT(Ahead Of Time) 预先编译,也就是分别有三种方式将字节码编译为本地机器码:
AOT 在 Android N 之前的预先编译方案是在应用安装时就预先编译成本地机器码,在 Android N 及之后是将在设备充电或闲置时开启一个后台进程编译。这在文章 JVM Hotspot 虚拟机与 Dalvik&ART 虚拟机堆栈的区别 有详细说明。 “类”的生命周期在开发语言中我们说到类就是指代的 Class,但这里说的不是这个 Class,而是代指的字节码文件。下面即将讲解字节码文件的生命周期,即从字节码文件到程序运行能够使用到卸载的过程。 字节码文件的读取解析通过前端编译器编译到字节码文件后,字节码文件信息如下: 我们可以思考一个问题:现在拿到了字节码文件,如果是由你设计一个后端编译器,你会怎么设计?或者换个说法,你会用哪些步骤解析上面的字节码,让程序跑起来? 既然生成的是文件,而且也放在磁盘里面,那 第一步首先就是要 IO 读取。 可以看到上图的字节码中有很多信息,例如 cafebabe 是一个魔数用于头校验确认是否是合法的字节码文件,如果字节码头文件不是这个就认为是无效的;还有各定义了 2 bytes 作为 Java 主版本号和副版本号;常量池计数器标记确认后面的字节码要读多少;还有其他信息等等。 可以发现这些数据项的顺序、一个或多个字节读取时所代表的是什么信息我们得先定义好,所以 第二步就是提前定义好专门的数据结构对数据项进行数据读取解析。 “类”的生命周期经过上面两个步骤,已经将字节码文件 IO 读取并且用提前定义好的数据结构解析完毕。但要让程序能够跑起来还是不够的,还需要将数据运行起来。所以需要具体的讲解“类”(字节码文件)的生命周期。 其中链接(Linking)又可以分为三个阶段:验证(Verification)-> 准备(Preparation)-> 解析(Resolution)。 加载阶段加载阶段加载的是什么? 加载阶段就是所谓的类加载,实际上指的是将字节码文件通过类加载器加载到方法区,并且在内存中构建出一个具体的承载类信息的实例对象 java.lang.Class(该数据处于运行时数据区-方法区),每个类都有一个 Class 类型的对象。 所以在加载阶段必须完成三件事情:
上面的步骤理解起来就是:将字节码文件读取到方法区->解析字节码文件的数据生成至堆区->生成 java.lang.Class。例如上面的例子就是将 Person 类的 name 和 getAge() 方法的数据信息给到 java.lang.Class,所以为什么在反射时为什么可以通过 class.getDeclaredField() 或 class.getDeclaredMethod() 能获取到类的信息,就是在这一步完成的。 需要注意的是,基本数据类型数组的加载并不是由类加载器负责创建,而是由 JVM 在运行时根据需要直接创建,数组不存在类加载的概念;其他的都通过类加载器加载。
链接阶段链接阶段分成了三个部分:验证 -> 准备 -> 解析。 准备阶段是为了给类的静态变量分配内存并赋值。这也是为什么我们在使用基本数据类型时能直接用会有默认值,就在这个阶段赋值的。静态数据是放在方法区,它有两个注意点:
解析阶段是为了将类、接口、字段、方法的符号引用转换为直接引用。 初始化阶段初始化阶段就是给给相关的变量去赋予初始值。
初始化阶段最重要的工作是执行初始化方法
使用阶段上面的 主动使用场景:
被动使用场景:
卸载阶段
上图中可以看到 Sample 类的 Class 对象和 ClassLoader 对象是双向关联的关系。 但要卸载 Sample 类对象腾出空间,就是让 GC Root 不可达才会被回收,所以要做到卸载需要断开 GC Root 的引用: 从字节码文件到类卸载步骤梳理上面已经具体分析了类的生命周期从字节码文件读取加载到类卸载的整个流程,接下来再简单梳理下所有步骤:
类加载器的分类在上面有讲到前端编译器编译代码后生成的 .class 文件是存放在磁盘中的,要将它解析读取到方法区就需要相关的工具,也就是类加载器。 类加载器的职责是 读取指定目录下的 .class 字节码文件和解析文件。
因为 JVM 的类加载器只支持单个 .class 字节码文件的读取,而 Android 是 .dex 文件是多个 .class 文件的集合,为了能够加载 .dex 文件 Android 是自己重写了一套类加载器,可以认为就是应用程序类加载器:
看上面的日志输出你可能会有疑惑:按照上面的类加载器关系,你说 Android 的类加载器是应用程序类加载器,那正常来讲 parent 就是扩展类加载器和启动类加载器才对,为什么会是 null? 需要注意的是,类加载器并不是继承关系,每个类加载器都是独立的,每个类加载器各自干自己的事情业务独立,加载代码的路径也不一样。所以说是类加载器分类,倒不如说是类加载器的种类。 在 Android 中 ART 虚拟机不等同与 JVM,上面有启动类加载器和扩展类加载器的那套体系是 JVM的,所以 Android 自己的一套类加载器体系不能和 JVM 的类加载器体系作比较。Android 的类加载器体系就是 BootClassLoader -> BaseDexClassLoader -> PathClassLoader。 类加载的步骤类加载器加载类有三个关键的方法:loadClass、findClass 和 defineClass。 loadClass
上面的步骤其实非常简单:
这个步骤就是所谓的双亲委派机制,如果一个类加载器在接到加载类的请求时,缓存找不到,会先委托父 ClassLoader 类加载器去加载,依次递归,都找不到才自己处理。 所以双亲委派机制它的本质是 ClassLoader 是带缓存的、会从上到下查找加载类的过程。 双亲委派机制其实在翻译为中文的时候是有误导的,在英文中双亲为 Parent,其实它只是一种往上委托 ClassLoader 查找类字节码的机制。 loadClass() 的作用就是为了完成双亲委派机制。类加载就是物理读取字节码文件的动作。 findClass、defineClass
父类 ClassLoader 对 findClass() 和 defineClass() 不做任何事情,而是将操作交由下面具体的 ClassLoader 处理。 findClass() 就是找到一个字节码文件的路径,然后读取这个字节码文件出来,形成一个字节码数组。 defindClass() 会将字节码文件读取完后进行校验(链接的验证阶段),该方法调用结束也就是类加载结束。 |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 21:27:34- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |