JVM是怎样初始化的?
JVM的初始,将class文件解析的过程。分为7个步骤
- 加载
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
加载阶段:点击程序运行
验证阶段:检测 .class 文件是否符合规范,是否被篡改
准备阶段:给每个写好的类分配一定的内存空间、给变量分配默认值
解析阶段:把符号应用替换为直接引用
- 符号引用:定位到目标的一种符号
- 直接引用:直接或间接指向目标,定位到目标
初始化阶段:给变量进行赋值(和准备阶段不同,准备阶段仅仅是赋值默认值)
贴一张图感受一下
在初始化阶段如果检测到 A 这个类存在父类,必须先加载、初始化这个父类。就会有类加载器的概念
类加载器
类加载器有4种
- 启动类加载器
- 扩展类加载器
- 应用程序类加载器
- 自定义类加载器
双亲委派机制
类加载的时候会存在类继承关系,会先加载父类,从上而下依次加载,如果父类无法完成这个任务,那么子加载器就需要自己完成加载。
JVM内存区域划分
-
方法区:存变量、方法、类(方法区在JDK1.8之后变成了MetaSpace(元空间))
-
字节码执行引擎:用来执行放在方法区里的内容
-
程序计数器:记录执行字节码指令的位置
-
java虚拟机栈:用来存放执行方法时的局部变量
-
java堆内存:存放实例之后的对象、变量
思考:为什么要记录指令位置?
因为程序可能是多线程执行的,所以要记录执行到哪个地方,并且每个线程都存在一个程序计数器
扩展一下java堆内存
其中有一块永久代,在JDK1.8之后也变成了 MetaSpace(元空间)
思考:永久带和方法区有什么关系,永久代=方法区吗
GC分代收集扩展至方法区,也可以说永久代实现了方法区。永久代是一种概念实现,方法区是一种定义规范。个人认为不用太过纠结,也可以直接看作永久代=方法区。
总结:
class文件会被加载到方法区中,字节码执行引擎会执行方法区中的内容,程序计数器会记录执行的位置,经过虚拟机栈进入堆内存