关于前端:Java虚拟机规范JVM类加载机制

38次阅读

共计 2144 个字符,预计需要花费 6 分钟才能阅读完成。

作者:threedayman

起源:恒生 LIGHT 云社区

理论知识

一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经验加载(Loading)、验证(Verification)、筹备(Preparation)、解析(Resolution)、初始化(Initialization)、应用(Using)和卸载(Unloading)七个阶段,其中验证、筹备、解析三个局部统称为连贯(Linking)。

《Java 虚拟机标准》严格规定了有且只有六种状况必须立刻对类进行“初始化”(而加载、验证、筹备天然须要在此之前开始)。

  • 遇到 new、getstatic、putstatic 或 invokestatic 这四条字节码指令时,如果类型没有进行过初始化,则须要先触发其初始化

应用 new 关键字实例化对象的时候。

读取或设置一个类型的动态字段(被 final 润饰、已在编译期把后果放入常量池的动态字段除外)。

调用一个类型的静态方法的时候。

  • 应用 java.lang.reflect 包的办法对类型进行反射调用的时候,如果类型没有进行过初始化,则须要先触发其初始化。
  • 当初始化类的时候,如果发现其父类还没有进行过初始化,则须要先触发其父类的初始化。
  • 当虚拟机启动时,用户须要指定一个要执行的主类(蕴含 main()办法的那个类),虚构机会先初始化这个主类。
  • 当应用 JDK 7 新退出的动静语言反对时,如果一个 java.lang.invoke.MethodHandle 实例最初的解析后果为 REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial 四种类型的办法句柄,并且这个办法句柄对应的类没有进行过初始化,则须要先触发其初始化。
  • 当一个接口中定义了 JDK 8 新退出的默认办法(被 default 关键字润饰的接口办法)时,如果有这个接口的实现类产生了初始化,那该接口要在其之前被初始化。

加载(Loading)

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

验证

  • 文件格式验证,验证字节流是否合乎 Class 文件格式的标准,并且能被以后版本的虚拟机解决。
  • 元数据验证,对字节码形容的信息进行语义剖析,以保障其形容的信息合乎《Java 语言标准》的要
    求。
  • 字节码验证,验证程序语义是非法的、合乎逻辑的。
  • 符号援用验证,验证是否短少或者被禁止拜访它依赖的某些外部类、办法、字段等资源,产生在将符号援用转换为间接援用得过程 – 解析阶段中产生。

筹备

为类变量分配内存并设置类变量初始值的阶段。

解析

Java 虚拟机将常量池内的符号援用替换为间接援用的过程。

初始化

进行筹备阶段时,变量曾经赋过一次零碎要求的初始零值,而在初始化阶段,则会依据程序员通
过程序编码制订的主观打算去初始化类变量和其余资源。

实例解说

JVM 在什么时候会去加载咱们得类呢?从实用得角度登程,就是在代码中用到这个类得时候。举个例子, 比方上面你有一个类(UserService.class),外面有一个“main()”办法作为主入口。那么一旦你的 JVM 过程启动之后,它肯定会先把你的这个类(UserService.cass)加载到内存里,而后从“main()”办法的入口代码开始执行。

public class UserService {public static void main(String[] args) {}}

接着咱们加上如下代码

public class UserService {public static void main(String[] args) {CarManager carManager = new CarManager();
    }
}

大家能够看到程序须要应用到 CarManager,此时就会触发 JVM 加载 CarManager 到内存里来应用。

验证

简略来说,这一步就是依据 Java 虚拟机标准,来校验你加载进来的“.class”文件中的内容,是否合乎指定的标准。免得 class 文件损坏或者被批改后不符合规范导致得 JVM 执行不了这个字节码。

筹备

筹备阶段会为类分配内存空间,给类变量调配空间并赋一个初始值。

public class UserService {private static int age;}

在筹备阶段中会给 age 变量赋初始值 0。

解析

将符号援用替换为间接援用

初始化

咱们先看下如下代码,咱们在什么时候通过 Configuration.getConfiguration(“sys.user.age”)获取到值并且赋值给 age?

public class UserService {private static int age = Configuration.getConfiguration("sys.user.age");
}

答案就是初始化阶段咱们会进行 Configuration.getConfiguration(“sys.user.age”)值获取并且赋值给 age 这个类变量。

以上就是本期内容,期待小伙伴们一起学习类加载机制,在评论区沟通交流。

参考

《深刻了解 java 虚拟机》

救火队长 -JVM 专栏

正文完
 0