虚拟机类加载机制

类从被加载到虚拟机内存,到卸载出内存为止,经历了7个阶段:加载、验证、准备、解析、初始化、使用、卸载。其中验证、准备、解析统称为连接。解析有时候在初始化后面,这是为了支持java语言的动态绑定。

  1. 加载:加载需要完成以下三件事

    • 通过一个类的全限定名来获取定义此类的二进制字节流;
      将这个字节流所代表的静态储存结构转化为方法区运行时数据结构;
      在内存中生存一个代表这个类的java.long.Class对象,作为方法区这个类的各种数据的访问入口。

  2. 验证:确保Class文件的字节流中包含的信息符合当前虚拟机的要求,不会危及虚拟机的自身安全。验证包含四个阶段的校验:文件格式验证、元数据验证、字节码验证、符号引用验证。

    • 文件格式验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。例如常量池中的常量是否有不被支持的常量类型、指向常量的各种索引值是否有指向不存在的常量或不符合类型的常量。
      元数据验:对字节码描述的信息进行语义分析,确保描述的信息符合java语言规范的要求。例如这个类是否有父类(除了Object类,一定有)、这个类是否继承了不允许被继承的类。
      字节码校验:通过数据流和控制流分析,确保程序语义是合法的。对类的方法体进行校验。例如保证方法体中的类型转换时有效的。
      符号引用验证对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验,保证了解析动作能正常执行。例如符号引用中通过字符串描述的全限定名是否能找到对应的类,符号引用中类、字段、方法的访问性(private,public等)能否被当前类访问。

    符号引用包含了三类变量:类和接口全限定名、字段名称和描述符、方法名称和描述符。

  3. 准备:准备阶段是正是为类变量分配内存并设置类变量初始值的阶段,这里设置的仅仅是被static修饰的类变量,初始值一般是数据类型的默认值0;public static int value = 123;准备阶段初始化value为0.

  4. 解析:将虚拟机常量池中的符号引用替换为直接引用。

    • 符号引用:以一组符号描述所引用的目标,符号引用可以是任何形式的字面量,只要能无歧义定位到目标。
      直接引用:就是直接指向目标的指针、相对偏移量或一个能间接定位到目标的句柄。

  5. 初始化:初始化时执行类构造器()方法(是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句产生的)。注意事项:

    • 一、静态语句块只能访问定义在静态语句块之前的变量,对于定义在它之后的变量,前面的静态语句块可以赋值,但不能访问。
      二、()方法和类构造器不同,虚拟机会保证子类()方法执行之前,父类的()方法已执行完毕
      三、执行接口的()方法不需要先执行父接口的()方法,只有当父接口定义的变量使用,父接口才会初始化。
      四、虚拟机会保证一个类的()方法在多线程环境下被正确的加锁、同步。

    虚拟机规定了有且只有5种情况对类进行初始化:

    • 遇到new、getstatic、putstatic、invokestatic四条字节码指令时。对应的场景是使用new关键字实例化对象、获取一个类的静态字段、设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)、调用一个类的静态方法。
      使用java.lang.reflect包的方法对类进行反射调用。
      初始化一个类时,如果发现其父类没有初始化,则需要先初始化其父类。
      虚拟机启动时,用户需要执行一个要执行的main类,虚拟机会先初始化这个类。
      如果java.lang.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄对应的类没有初始化,则先初始化这个类。

  6. 使用

  7. 卸载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值