JVM超神之路
本篇博客转载自微信公众号
Java知音
《JVM超神之路:年后跳槽需要的JVM知识点,周末给你整理了一份!!!》 (opens new window)
# 一、ClassLoader类加载器
# 类加载过程
# 加载
将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存 上创建一个java.lang.Class对象用来封装类在方法区内的数据结构作为这个类各种数据的访问 入口
# 验证
主要是为了确保class文件中的字节流包含的信息是否符合当前JVM的要求,且不会危害JVM自身安 全,比如校验文件格式、是否是cafe baby魔术、字节码验证等等。
# 准备
为类变量分配内存并设置类变量(是被static修饰的变量,变量不是常量,所以不是final的,就是 static的)初始值的阶段。这些变量所使用的内存在方法区中进行分配。比如
private static int age = 26;
1
类变量age会在准备阶段过后为 其分配四个(int四个字节)字节的空间
注意
设置初始值为0,而不是26,若是final的,则在编译期就会设置上最终值。
# 解析
JVM会在此阶段把类的二进制数据中的符号引用替换为直接引用。
是什么是符号引用和直接引用?
1. 符号引用:字符串,能根据这个字符串定位到指定的数据,比如java/lang/StringBuilder
2. 直接引用:内存地址
类加载之后,常量池的内容会进入运行时常量池,这时候里面的数据也许还保持着符号引用。
(因为解析的时机由JVM自己设定)
如果在虚拟机栈的 栈帧中,我准备调用 main() 函数,那么会通过栈帧中持有的动态连接,找到运行时常量池,
然后找到main函数的常量 比如 #2 ,如果这个常量没有被解析过,那么就通过这个常量进行解析过程,
其中包括,通过常量 找到 类名 和 nameAndType,通过 nameAndType 找到方法名和返回值。
这时候 我手里有 类名/方法名/方法返回值,下一步,我通过类名和方法名,通过JVM记录的方法列表,找到对应的方法体。
而这个方法体实际上是一段内存地址,那么这时候我就把这段内存地址复制给 #2,并且给 #2设定一个已经解析的 flag。
这样就完成了 符号引用到直接引用的过程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 初始化
初始化阶段是执行类构造器<clinit>()
方法的过程,到了初始化阶段,才真正开始执行类定义的
Java程序代码(或者说字节码 )。比如准备阶段的那个age初始值是0,到这一步就设置为26。
# 使用
对象都出来了,业务系统直接调用阶段。
# 卸载(回收)
用完了,可以被GC回收了。
# 类加载器种类以及加载范围
# 应用类加载器
最顶层类加载器,他的父类加载器是个null,也就是没有父类加载器。负责加载jvm的核心类库, 比如java.lang.*等,从系统属性中的sun.boot.class.path所指定的目录中加载类库。他的 具体实现由Java虚拟机底层C++代码实现。
未完待续……
编辑 (opens new window)
上次更新: 2021/12/20, 09:41:36