【JVM】类加载机制

Class 文件结构

Java 字节码文件主要包括以下几部分:

  • 魔数与class 文件的版本
  • 常量池
  • 访问标志:表示该 class 的属性和访问类型,该 class 是类还是接口,是不是 public,是否被 final 修饰
  • 类索引、父类索引、接口索引
  • 字段表属性:用于描述接口或类中描述的变量。比如变量的作用域(public、peivate),是否是静态变量(static),可变性(final),数据类型(基本类型、对象、数组)等等
  • 方法表属性:和字段表类似,描述的是方法的属性
  • 属性表属性:用于描述某些特定场景专有的信息

常量池

常量池主要存放两大类:字面量和符号引用。字面量类似于Java的常量的概念,如文本字符串,final常量等。符号引用包括以下三种:

  • 类和接口的全限定名
  • 变量的名称和描述符号
  • 方法的名称和描述符
    JVM 是在类加载阶段才开始进行动态链接的,也就是说这些字段和符号引用只有在运行期转换后才能获取真正的内存入口地址

Java 类加载机制

类加载主要分为三个阶段:加载、连接和初始化;连接阶段又可分为:验证、准备和解析

加载阶段:查找并加载类的二进制数据

加载阶段主做三件事情:

  • 通过类的全限定名来获取类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 在 Java 堆中生成一个 java.lang.class 对象,作为对方法区中这些数据的访问入口
    加载阶段总结:查找并加载类的二进制数据,并在 JVM 堆中创建一个 class 对象,并且将类的信息保存至方法区

连接阶段

验证:验证是否符合 Java 规范和 JVM 的规范

验证阶段主要进行的是对文件格式的验证、元数据验证、字节码验证和符号引用验证

准备:为类的静态变量分配内存,并初始化为默认值

准备阶段正式为变量分配内存并设置变量的初始值,这些内存都是在方法区中分配的。

  • 在准备阶段进行内存分配的只有类变量(static),实例变量会在对象实例化时随着对象在堆中一起分配内存
  • 在准备阶段为变量赋的初始值都是默认值(0, null, 0L, false)
解析:把类中的符号引用转换为直接引用

解析阶段是虚拟机将常量池内符号引用转换为直接引用的过程,符号引用包括类和接口的全限定名、变量的名称和描述符号、方法的名称和描述符。直接引用就是指向目标的指针。

初始化:为静态变量赋予正确的初始值

初始化阶段主要就是为静态变量赋予初始值

初始化时机:

  • 使用 new 创建类的实例
  • 访问类或接口的静态变量或对静态变量赋值
  • 访问类的静态方法
  • 反射
  • 初始化某个子类其父类也会初始化
  • 启动类

类加载器 类加载机制

类加载器

BootStrapClassLoader -> ExtClassLoader -> AppClassLoader -> User ClassLoader

类加载机制:双亲委派机制

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。

  1. 当 AppClassLoader 要加载一个 class 时,他首先不会自己尝试去加载这个类,而是将加载类的任务委托给父类 ExtClassLoader 去完成
  2. 当 ExtClassLoader 要加载一个 class 时,他首先不会自己尝试加载这个类,而是把类加载请求委托给 BootStrapClassLoader 去完成
  3. 如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载;
  4. 若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException。
相关推荐
码老白5 分钟前
【老白学 Java】Warshipv2.0(二)
java·网络
苹果酱05676 分钟前
前端面试vue篇:Vue2 和 Vue3 在设计和性能上有显著区别
java·spring boot·毕业设计·layui·课程设计
万琛18 分钟前
【java-Neo4j 5开发入门篇】-最新Java开发Neo4j
java·neo4j
Bald Baby37 分钟前
JWT的使用
java·笔记·学习·servlet
魔道不误砍柴功42 分钟前
实际开发中的协变与逆变案例:数据处理流水线
java·开发语言
Rverdoser1 小时前
RabbitMQ的基本概念和入门
开发语言·后端·ruby
dj24429457071 小时前
JAVA中的Lamda表达式
java·开发语言
工业3D_大熊1 小时前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化
szc17671 小时前
docker 相关命令
java·docker·jenkins