虚拟机类加载机制

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。(不要把类加载和类加载中的一步“加载”混淆)

一、概述

在这里插入图片描述
类的整个生命周期包括:加载,验证,准备,解析,初始化,使用,卸载7个阶段,其中验证、准备、解析3个部分统称为链接。

二、类加载的过程

2.1 加载

“加载”是“类加载”过程的一个阶段,在加载阶段,虚拟机需要完成以下三件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为方法区(元空间)的运行时数据结构,内部采用C++的instanceKlass描述Java类
  3. 在堆中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据的访问入口
    在这里插入图片描述
    上述过程可以用下图来表示,在jdk1.8之后,方法区被移至Metaspace。在元空间中,类文件用C++的instanceKlass这种数据结构来描述,其中有一项_java_mirror指向储存在堆中class对象,作用是把该数据结构暴露给java使用。
    每个实例对象都有对象头,其中有一部分是类型指针,该指针指向该类的class对象

2.2 验证

验证是连接阶段的第一步,目的是确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

2.3 准备

为static变量分配内存空间,设置默认值

  • 在jdk1.8中,static变量存储在堆中
  • static变量分配空间和赋值是两个步骤,分配空间在准备阶段完成,赋值在之后的初始化阶段完成(之前介绍的cinit方法)
  • 如果static变量是final的基本类型,以及字符串常量,那么编译阶段就能确定,赋值在准备阶段完成
  • 如果static变量是final的引用类型,那么赋值也会在初始化阶段完成

2.4 解析

将常量池内的符号引用替换为直接引用的过程


  • 符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用于虚拟机实现的内存布局无关,引用的目标不一定已经加载到内存中。
  • 直接引用:可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用和虚拟机实现的内存布局相关,同一个符号引用载不同虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在内存中存在。

2.5 初始化

Java虚拟机规范中没有强制约束什么时候开始加载,但是严格规定了只有在5种情况下必须立即对类进行“初始化”:

  1. 使用new关键字实例化对象的时候
  2. 首次访问类的静态变量或静态方法时。
  3. Class.forName
  4. 子类初始化,如果父类还没初始化,会引发
  5. 虚拟机启动时,初始化主类(main类)
    以上五种情况被称为类的主动引用。除此之外,所有引用类的方式都不会出发初始化,成为被动引用,有以下三种情况:
  6. 类对象.class不会触发初始化(在加载阶段就已经生成了_java_mirror对象,不需要初始化)
  7. 创建该类的数组不会触发初始化
  8. 类加载器的loadClass方法
  9. Class.forName的参数2位false时
  10. 访问类的static final静态常量(基本类型和字符串)不会初始化
    初始化阶段即调用(),()是由编译器自动收集类中所有类变量的复制动作和静态语句快中的语句合并产生的,收集顺序按照在源文件中出现的顺序决定。对于定义在静态语句块之后的变量,静态语句块可以赋值,但是不能访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值