【JVM知识总结-9】类加载的过程

盗梦空间
• 阅读 883

【JVM知识总结-1】JVM内存模型
【JVM知识总结-2】HotSpot虚拟机对象
【JVM知识总结-3】垃圾收集策略与算法
【JVM知识总结-4】HotSpot垃圾收集器
【JVM知识总结-5】内存分配与回收策略
【JVM知识总结-6】JVM性能调优
【JVM知识总结-7】类的文件结构
【JVM知识总结-8】类的加载时机
【JVM知识总结-9】类加载的过程
【JVM知识总结-10】类加载器

类的加载过程包括5个阶段:加载、验证、准备、解析和初始化。

加载

加载的过程

“加载”是“类加载”过程的一个阶段,不能混淆这两个名词。在加载阶段,虚拟机需要完成3件事:

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

获取二进制字节流

对于Class文件,虚拟机没有指名要从哪里获取、怎样获取。除了直接编译好的.class文件中读取,还有以下几种方式:

  • 从zip包中读取,如jar、war等
  • 从网络中获取,如Applet;
  • 通过动态代理技术生成代理类的二进制字节流;
  • 由JSP文件生成对应的Class类
  • 从数据库中读取,如有些中间件服务器可以把选择程序安装到数据库中来完成程序代码在集群间的分发。

“非数组类”与“数组类”的加载比较

  • 非数组类加载阶段可以使用系统提供的引导类加载器,也可以由用户自定义的类加载器完成,开发人员可以通过定义自己的类加载器控制字节流的获取方式(如重写一个类加载器的loadClass()方法)。
  • 数组本类本身不通过类加载器创建,它是由Java虚拟机直接创建的,再由类加载器创建数组中的元素类。

注意事项

  • 虚拟机规范未规定Class对象的存储位置,对于HotSpot虚拟机而言,Class对象比较特殊,它虽然是对象,但存放在方法区中。
  • 加载阶段与连接阶段的部分内容交叉进行,加载阶段尚未完成,连接阶段可能已经开始了。但这两个阶段的开始时间仍然保持着固定的先后顺序。

验证

验证的重要性

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

验证的过程

  • 文件格式验证:验证字节流是否是符合Class文件格式的规范,并且能被当前版本的虚拟机处理,验证点如下:

    • 是否魔数0xCAFEEBABE开头
    • 主次版本号是否在当前虚拟机处理范围内
    • 常量池是否有不被支持的常量类型
    • 指向常量的索引值是否指向了不存咋的常量
    • CONSTANT_Utf8_info型的常量是否有不符合UTF8编码的数据。
    • ...
  • 元数据验证:对字节码描述信息进行语义分析,确保其符合Java语言规范
  • 字节码验证:本阶段是验证过程中最复杂的一个阶段,是对方法体进行语义分析,保证方法在运行时不会出现危害虚拟机的事件。
  • 符号引用验证:本阶段发生在解析阶段,确保解析正常执行。

准备

准备阶段是正式为变量(或称“静态成员变量”)分配内存并设置初始值的阶段。这些变量(不包含实例变量)所使用的内部都在方法区中进行分配。
初始值“通常情况下”是数据类型的零值(0,null),假设一个类变量的定义为:

public static int value = 123;

那么变量value在准备阶段过后的初始值未0而不是123,因此这时候尚未开始执行任何Java方法。
存在“特殊情况”:如果类字段的字段属性表中存在ConstantValue属性,那么在准备阶段value就会被初始化为ConstantValue竖向所指定的值,假设上面类变量value的定义变为:

public static final int value = 123;

那么在准备阶段虚拟机会根据ConstantValue的设置将value赋值为123。

解析

解析阶段是虚拟机将常量池中的符号引用的过程。

初始化

类初始化阶段是类加载过程的最后一步,是执行类构造器<clinit()>()方法的过程。
<clinit()>()方法是由编译器自动收集类中的所有类变量的复制动作和静态语句块(static{})中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序锁决定的。
静态语句块中只能访问定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块中可以赋值,但不能访问,如下代码所示。

public class Test {
    static {
        i = 0;  // 给变量赋值可以正常编译通过
        System.out.println(i);  // 这句编译器会提示“非法向前引用”
    }
    static int i = 1;
}

<clinit()>()方法不需要显示调用父类构造器,虚拟机会保证在子类的<clinit()>()方法执行之前,父类的<clinit()>()方法已经执行完毕。
由于父类的<clinit()>()方法先执行,意味着父类中定义的静态语句块要优先于子类的变量赋值操作。

static class Parent {
    public static int A = 1;
    static {
        A = 2;
    }
}

static class Sub extends Parent {
    public static int B = A;
}

public static void main(String[] args) {
    System.out.println(Sub.B); // 输出 2
}

<clinit()>()方法不是必须的,如果一个类没有静态语句块,也没有对类变量的赋值操作,那么编译器可以不为这个类生成<clinit()>()方法。
接口中不能使用静态代码块,但接口也需要通过<clinit()>()方法为接口中定义的静态成员变量显式初始化。但接口与类不同,接口的<clinit()>()方法不需要先执行父类的<clinit()>()方法,只有当父类接口中定义的变量使用时,父接口才会初始化。
虚拟机会保证一个类的<clinit()>()方法在多线程环境中被正确加锁、同步。如果多线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit()>()方法。

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java基础知识随身记
2018年11月12日20:51:35一、基础知识:1、JVM、JRE和JDK的区别:JVM(JavaVirtualMachine):java虚拟机,用于保证java的跨平台的特性。  java语言是跨平台,jvm不是跨平台的。JRE(JavaRuntimeEnvironment):java的运行环境,包括jvmjava的核心类
Wesley13 Wesley13
3年前
java 虚拟机 收集器 总结
java虚拟机收集器总结|垃圾收集器|新生代|老年代|jvm参
Wesley13 Wesley13
3年前
Java 开发岗面试知识点解析
在不断的面试中,分类总结了Java开发岗位面试中的一些知识点。主要包括以下几个部分:1.Java基础知识点2.Java常见集合3.高并发编程(JUC包)4.JVM内存管理5.Java8知识点6.网络协议相关7.数据库相关8.MVC框架相关9.大数据相关10.Linux命令相
Stella981 Stella981
3年前
JVM参数说明介绍
1.JVM运行时数据区内存参数说明!(https://oscimg.oschina.net/oscnet/051d0ecafbef225b7b495ff43f6aec3173d.png)2.JVM垃圾收集器参数总结!(https://oscimg.oschina.net/oscnet/c2d0b716ad17c45ae776caa
Stella981 Stella981
3年前
JVM(二)Java虚拟机组成详解
导读:详细而深入的总结,是对知识“豁然开朗”之后的“刻骨铭心”,想忘记都难。Java虚拟机(JavaVirtualMachine)下文简称jvm,上一篇我们对jvm有了大体的认识,进入本文之后我们将具体而详细的介绍jvm的方方面面,而本文主要讲的是jvm的组成,了解了它,就揭开了jvm的神秘面纱。一、jvm的主要组成部分
Stella981 Stella981
3年前
JVM系列【6】GC与调优2
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优了解HotSpot常用命令行参数JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/
Stella981 Stella981
3年前
JVM系列【6】GC与调优1
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优GC基础知识什么是垃圾​没有任何引用指向的一个对象或多个对象(循环引用)!file(https:
Stella981 Stella981
3年前
JVM系列【6】GC与调优3
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优调优前的基础概念1.吞吐量:用户代码时间/(用户代码执行时间垃圾回收时间)2.响应时间:STW越短,响应时间越好3.
Stella981 Stella981
3年前
JVM运行机制(非原创)
文章大纲1.JVM基本概念2.JVM的体系结构3.JVM启动流程一、JVM基本概念1.Java虚拟机(JVM)是可运行Java代码的假想计算机2.Java虚拟机包括类加载器、一组寄存器、方法区、一个垃圾回收堆、直接内存、一个栈、和一个存储方法域、PC寄存器等3.Java编译、运行流程如
Stella981 Stella981
3年前
JVM的艺术—JAVA内存模型
\喜欢文章,动动手指点个赞\引言亲爱读者你们好,关于jvm篇章的连载,前面三章讲了类加载器,本篇文章将进入jvm领域的另一个知识点,java内存模型。彻底的了解java内存模型,是有必要的。只要掌握了java的内存模型,内存空间分为哪些区域,才能更好地理解,java是如何创建对象以及如何分配对象的空间。对后续的jvm调优打下坚实