阅读更多精彩文章,欢迎关注微信公众号:深夜程猿
从类的加载说起
在谈JVM核心运行流程之前,我们先说下java的类加载机制。
我们知道,java的类加载机制采取的是双亲委派机制。
所谓双亲委派机制,也就是说在加载一个类的时候,先一步一步往上传递由最顶层的类加载器加载,加载不到就交给直接下一层类加载器加载,一步一步往下传递,直到某一个类加载器加载到类才结束加载。如果所有的类加载器都不能加载到该类,那么就会抛出类找不到的异常
在java虚拟机规范中,定义了三种类加载器,分别是:
- 引导类加载器:BootstrapClassLoader
最顶层的类加载器
- 扩展类加载器:ExtensionClassLoader
BootstrapClassLoader加载器的子类
- 应用类加载器:ApplicationClassLoader
扩展类加载器的子类
此外我们还可以自定义自己的类加载器。
一个类从加载到使用,其生命周期有七个阶段:
- 加载阶段
加载.class文件到JVM内存
- 验证阶段
根据JVM规范验证.class是否合法
- 准备阶段
主要是给类分配内存空间,这个阶段会计算出类需要占用多大的内存空间
- 解析阶段
主要是把符号引用改为直接引用
- 初始化阶段
真正的为类进行初始化,包括静态代码块的执行,类的全局变量的赋值操作
- 使用阶段
经过类的初始化阶段,类就可以被JVM中的线程使用了
- 卸载
有些类不再被使用或者由于内存紧张,短期内不会使用到的类就会从JVM内存中移除,等到下一次需要它们的时候再加载进来
上面和大家说说了类的加载各个阶段,这里不深入讨论每一个阶段的细节,大家有个整体的流程印象就可以了。
JVM的内存模型
.class文件加载到JVM内存中,需要对类的不同的东西进行分门别类的存储起来,方便管理和使用。在JVM内存中,主要分出四大块内存区域来存储和管理类:
- 方法区
存储类的信息和静态常量
- 堆内存
用来存储类的对象
- 程序计数器
这是线程独立的一个内存块,用来记录在线程中程序指令执行的位置
- 虚拟机栈
这也是线程独立的,该内存区域会维护一个方法栈,每调用一次方法都会往方法栈加入一个方法调用记录,方法执行完毕再出栈。该内存区域还会存储方法的局部变量
总的来说,每一个java应用都对应这一个JVM进程。在JVM进程中,需要使用到类的时候,就会把类加载到JVM进程中。经过多个阶段加载进来的类,JVM会分门别类在不同的内存区域存储类的信息,方便后续管理和使用。
一张图总结JVM核心运行流程
总的来说,JVM的核心运行流程实际就是类被加载到JVM进程的过程,以及在JVM内存中对类的存储和管理过程。下面用一张图给大家总结以下JVM的核心运行流程。