JVM类加载机制

JVM在什么情况下会加载一个类

当系统代码执行过程中,需要使用到这个类的时候,就会加载这个类。

一个类加载的过程

一个类的加载过程包括: 加载->验证->准备->解析->初始化->使用->卸载
加载:JVM将编译好的.class文件加载到JVM的内存中。
验证:验证加载至JVM内存的.class文件是否符合JVM规范,如果不符合,则无法进行下一步。
准备:给加载的类分配内存空间,同时针对类静态变量也分配空间,静态变量默认初始值(比如整数0)赋值。
解析:符号引用转为直接引用,即将变量转为计算机可以识别的字节地址。
初始化:真正将静态变量赋值(准备阶段只是给了初始值),同时执行静态代码块。执行的顺序,需要先初始化父类,再初始化子类。(类加载器中最核心的流程)。

类加载器

启动类加载器:主要加载Java目录下的核心类,即:jdk/lib目录下的类。
扩展类加载器: 主要加载java目录下的扩展类,即:jdk/lib/ext目录下的类。
应用程序类加载器:负责加载项目classpath下的类,即:target/WEB-INF/classes目录下的类。
自定义类加载器:自定义类加载器,比如tomcat的Catalina类加载器等。


双亲委派机制

对于一个类的加载,子类加载器会委派给自己的父类加载器去尝试加载,这个过程会一直传递到顶级的类加载器(即启动类加载器)。如果顶级类加载器无法加载这个类,则再交由自己子类加载器去尝试加载,如果所有的父类加载器都无法加载这个类,就由最后的子类加载器去加载。

委派流程: 应用类加载器 —-(委派)—-> 扩展类加载器 —- (委派) —-> 启动类加载器 —-(无法加载) —-> 扩展类加载器 —-(无法加载)—->应用类加载器(加载)

主要的目的是,防止存在多个类加载器加载同一个类,造成重复加载。
Tomcat的类加载机制是打破双亲委派机制的。

Tomcat的类加载器的设计

JVM内存区域

方法区(永久代)/元数据空间

主要存储类以及类的静态变量

程序计数器(线程私有)

主要负责记录每一个线程执行字节码指令的位置。

虚拟机栈(线程私有)

每调用一个方法,就向指定线程的虚拟机栈推入一个栈帧(先入后出)。栈帧主要包含:局部变量信息,动态链接,操作数栈,方法出口等东西。

本地方法栈(线程私有)

调用原生方法native(),存放原生方法的局部变量等信息。

堆内存

存储方法调用过程中,new出来的对象。虚拟机栈的方法下的局部变量引用堆内存中的对象。局部变量保存的是堆内存的物理地址,堆内存中是真正存储对象内容的地方。