关于jvm:类的加载过程

2次阅读

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

类的生命周期

JVM 类加载机制分为五个局部:加载 验证 筹备 解析 初始化,上面咱们就别离来看一下这五个过程。其中加载、测验、筹备、初始化和卸载这个五个阶段的程序是固定的,而解析则未必。为了反对动静绑定,解析这个过程能够产生在初始化阶段之后。

加载:

加载过程次要实现三件事件:

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

这个过程次要就是类加载器实现。

校验:

此阶段次要确保 Class 文件的字节流中蕴含的信息合乎以后虚拟机的要求,并且不会危害虚拟机的本身平安。

  1. 文件格式验证:基于字节流验证。
  2. 元数据验证:基于办法区的存储构造验证。
  3. 字节码验证:基于办法区的存储构造验证。
  4. 符号援用验证:基于办法区的存储构造验证。

筹备:

为类变量分配内存,并将其初始化为默认值。(此时为默认值,在初始化的时候才会给变量赋值)即在办法区中调配这些变量所应用的内存空间。例如:

public static int value = 123;

此时在筹备阶段过后的初始值为 0 而不是 123;将 value 赋值为 123 的 putstatic 指令是程序被编译后,寄存于类结构器 <client> 办法之中. 特例:

public static final int value = 123;

此时 value 的值在筹备阶段过后就是 123。

解析:

把类型中的符号援用转换为间接援用。

  • 符号援用 与虚拟机实现的布局无关,援用的指标并不一定要曾经加载到内存中。各种虚拟机实现的内存布局能够各不相同,然而它们能承受的符号援用必须是统一的,因为符号援用的字面量模式明确定义在 Java 虚拟机标准的 Class 文件格式中。
  • 间接援用 能够是指向指标的指针,绝对偏移量或是一个能间接定位到指标的句柄。如果有了间接援用,那援用的指标必然曾经在内存中存在

次要有以下四种:

  1. 类或接口的解析
  2. 字段解析
  3. 类办法解析
  4. 接口办法解析

初始化:

初始化阶段 是执行类结构器 <client> 办法的过程。<client> 办法是由编译器主动收集类中的类变量的赋值操作和动态语句块中的语句合并而成的。虚构机会保障 <client> 办法执行之前,父类的 <client> 办法曾经执行结束。如果一个类中没有对动态变量赋值也没有动态语句块,那么编译器能够不为这个类生成 <client>()办法。

java 中,对于初始化阶段,有且只有以下五种状况才会对要求类立即“初始化”(加载,验证,筹备,天然须要在此之前开始):

  1. 应用 new 关键字实例化对象、拜访或者设置一个类的动态字段(被 final 润饰、编译器优化时曾经放入常量池的例外)、调用类办法,都会初始化该动态字段或者静态方法所在的类。
  2. 初始化类的时候,如果其父类没有被初始化过,则要先触发其父类初始化。
  3. 应用 java.lang.reflect 包的办法进行反射调用的时候,如果类没有被初始化,则要先初始化。
  4. 虚拟机启动时,用户会先初始化要执行的主类(含有 main)
  5. jdk 1.7 后,如果 java.lang.invoke.MethodHandle 的实例最初对应的解析后果是 REF_getStatic、REF_putStatic、REF_invokeStatic 办法句柄,并且这个办法所在类没有初始化,则先初始化。

类加载器:

把类加载阶段的“通过一个类的全限定名来获取形容此类的二进制字节流”这个动作交给虚拟机之外的类加载器来实现。这样的益处在于,咱们能够自行实现类加载器来加载其余格局的类,只有是二进制字节流就行,这就大大加强了加载器灵活性。零碎自带的类加载器分为三种:

启动类加载器。
扩大类加载器。
应用程序类加载器。

双亲委派机制

双亲委派机制工作过程

如果一个类加载器收到了类加载器的申请. 它首先不会本人去尝试加载这个类. 而是把这个申请委派给父加载器去实现. 每个档次的类加载器都是如此. 因而所有的加载申请最终都会传送到 Bootstrap 类加载器 (启动类加载器) 中. 只有父类加载反馈本人无奈加载这个申请 (它的搜寻范畴中没有找到所需的类) 时. 子加载器才会尝试本人去加载。

双亲委派模型的长处:java 类随着它的加载器一起具备了一种带有优先级的档次关系.

例如类 java.lang.Object, 它寄存在 rt.jart 之中. 无论哪一个类加载器都要加载这个类. 最终都是双亲委派模型最顶端的 Bootstrap 类加载器去加载. 因而 Object 类在程序的各种类加载器环境中都是同一个类. 相同. 如果没有应用双亲委派模型. 由各个类加载器自行去加载的话. 如果用户编写了一个称为“java.lang.Object”的类. 并存放在程序的 ClassPath 中. 那零碎中将会呈现多个不同的 Object 类.java 类型体系中最根底的行为也就无奈保障. 应用程序也将会一片凌乱.

正文完
 0