JVM底层体系

代码编译的结果从本地机器指令码转化为字节码,是存储格式发展的一小步,但却是编程语言发展的一大步

​ —— 《深入理解JVM虚拟机》周志明·著

​ Java虚拟机将描述类的数据从class字节码文件加载到内存,并且对数据进行校验,转化,解析,初始化的工作,最终形成在内存中可以直接使用的数据类型。
这个过程叫做虚拟机的类加载机制。

图示

类加载子系统

作用

  • 类加载子系统负责从文件系统或者网络中加载Class文件(Class文件在开头有特定标识)。
  • l类加载器(Class Loader)只负责class文件的加载,至于是否可以运行,由执行引擎(Execution Engine)决定。
  • 加载的类信息存放于一块成为方法区的内存空间。除了类信息之外,方法区还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

类加载器扮演的角色

image-20210617111632499

  • Car.class存放于本地硬盘中,在运行的时候,JVM将Car.class文件加载到JVM中,被称为DNA元数据模板

    存放在JVM的方法区中,之后根据元数据模板实例化出相应的对象。

  • .class -> JVM -> 元数据模板 -> 实例对象 这个过程中,类加载器扮演者快递员的角色。

类加载的时机

关于类加载的时机,《Java虚拟机规范》中并没有明确规定。这点可以由虚拟机的具体实现决定。

但是类的初始化阶段,规范中明确规定当某个类没有进行初始化,只有以下6中情况才会触发其初始化过程。

  1. 遇到new,getStaticputStatic,invokeStatic,这四条字节码指令的时候,如果改类型没有进行初始化,则会触发其初始化。也就是如下情况
    1.1. 遇到new关键字进行创建对象的时候。
    1.2. 读取或者设置一个类的静态字段的时候(必须被final修饰,也就是在编译器把结果放入常量池中)。
    1.3. 调用一个类的静态方法的时候。
  2. 使用java.lang.reflect进行反射调用的时候。
  3. 当初始化某个类,发现其父类没有初始化的时候。
  4. 当虚拟机启动的时候,会触发其主方法所在的类进行初始化。
  5. 当使用JDK1.7中的动态语言支持时,如果一个java.lang.invoke.MethidHandle实例最后的解析结果为REF_getStatic,REF_putStatic,REF_invokeStatic
    ,REF_newInvokeSpecial四种类型的方法句柄,并且这个句柄对应的类没有被初始化。
  6. 当一个接口实现了JDK1.8中的默认方法的时候,如果这个接口的实现类被初始化,则该接口要在其之前进行实例化。

对于以上6中触发类的初始化条件,在JVM规范中有一个很强制的词,if and only if (有且只有)。这六种行为被称为对类进行主动引用,除此之外,其他引用类的方式均不会触发类的初始化。