图解JVM类加载机制和双亲委派模型
我们都知道以 .java
结尾的 java 源文件,经过编译之后会变成 .class
结尾的字节码文件。jvm 通过类加载器来加载字节码文件,然后再执行程序。
什么时候加载一个类
那么,什么时候类加载器会加载一个类呢?用到这个类的时候,jvm的类加载器就会加载这个类。用到这两个字说起来很抽象,我用代码和图例来说明。
有下面这样一段代码,一个类emergencyplan
,里面有一个main()
函数,main()
函数做的事情是创建了一个 account 对象。
public class emergencyplan { public static void main(string[] args) { account account = new account(); } }
我们应该知道运行 jvm 就相当于启动了一个 java 的进程,它会从程序的主函数,即main()
函数开始执行。所以类加载的步骤是这样的:
- 先加载主函数所在的类
emergencyplan
- 由于
emergencyplan
使用了account
,所以继续加载account
准备和初始化的区别
类加载机制总共有这样7个步骤:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载。接下来先把每个阶段在做什么讲一下,再着重对比一下准备阶段和初始化阶段。
- 验证阶段:验证字节码文件是否符合jvm的规范。这挺好理解,万一字节码文件被修改过,jvm压根无法执行咋办。所以加载之后先验证一下。
- 准备阶段:为类分配内存空间,为变量赋初值。
- 解析阶段:符号引用替换为直接引用。
- 初始化阶段:执行初始化代码,new对象;执行static代码块;父类没有初始化要先初始化父类。
用代码和画图来说明一下准备阶段和初始化阶段。
public class emergencyplan { public static int id = configuration.getint("plan_id"); }
这段代码说的是emergencyplan
这个类有一个变量id
,通过getint()
为其赋值:
- 准备阶段会为
id
开辟一个内存空间,但不会执行赋值操作,仅仅是赋予一个初值0。 - 初始化阶段才会执行
getint()
为变量id
初始化值。
类加载的过程就变成了下图所示的样子:
类加载器和双亲委派模型
jvm进行类加载是通过类加载器完成,类加载器是一种亲子层级结构的模型。java里面的类加载器有这样几种:
- 启动类加载器。加载 jdk 中 lib 目录中 java 的核心类库,即
$java_home/lib
目录。 - 扩展类加载器。加载 lib/ext 目录下的类。
- 应用程序类加载器。加载我们写的应用程序。
- 自定义类加载器。根据自己的需求定制类加载器。
那什么是双亲委派模型呢?类加载器是一种亲自层级结构,就像下图所示:
比如要加载上面的emergencyplan
类,应用程序类加载器会先问它的父亲扩展类加载器,你能帮我加载么?扩展类加载器会再问它的父亲启动类加载器,你能帮我加载么?
显然emergencyplan
是一个应用程序类。启动类加载器会告诉扩展类加载器,你自己去加载;扩展类加载器就会告诉应该程序类加载器,你自己去加载。最后,应用程序类加载器就自己加载了emergencyplan
。
流程图总结
最后来在类加载的流程图上,把双亲委派模型也添加上去。
上一篇: 尚硅谷JDBC学习笔记
下一篇: JVM内存结构图
推荐阅读
-
[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的
-
图解JVM类加载机制和双亲委派模型
-
【java基础】面试常见问题:类和对象,封装继承多态,final关键字,static关键字,类加载过程,双亲委派模型
-
荐 【JVM】JVM类加载机制(类加载过程和类加载器)
-
类加载器和双亲委派模型
-
【深入理解JVM】1、在JVM类加载如何加载?双亲委派加载类及混合模式,代码演示【面试必备】
-
类加载器与双亲委派机制
-
荐 java类加载过程及双亲委派机制
-
JVM入门(位置、体系结构、类加载器、双亲委派机制、沙箱安全机制、Native、PC寄存器、方法区、堆(新生区{伊甸园区、幸存区}、养老区、永久区)、OOM、GC算法、JMM)
-
[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的