JVM类加载机制

类加载时机

  • 加载
  • 验证
  • 准备
  • 解析
  • 初始化
  • 使用
  • 卸载

加载

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

加载二进制流的手段:

  1. 从zip包中获取,如jar
  2. 从网络中获取,Applet
  3. 运行时计算生成,动态代理
  4. 由其他文件生成,jsp
  5. 从数据库中读取,较少

注意:

数组类由不通过类加载器创建,而由虚拟机直接创建。

  1. 如果数组的组件类型(每一个值)是引用类型,则递归采用类的家在过程去加载
  2. 如果不是引用类型,而是int[]中,将数组标记为与引导类加载器关联
  3. 如果不是引用类型,则数组的可见类型默认为public

验证

  1. 文件格式验证,验证字节流是否符合Class文件格式的规范,并且是否能被虚拟机处理(版本号是否在处理范围)。
  2. 元数据验证 进行语义分析。
  3. 字节码验证 确定程序语义是否合法、符合逻辑。
  4. 符号引用验证 发生在虚拟机将符号引用转化为直接引用的时候。

准备

为类变量分配内存并设置类变量的初始值,这些变量所使用的内存都在方法区进行分配。这里只包括类变量,不包括实例变量。

  1. 内存分配的仅包括类变量(static),而不包括实例变量。
  2. 这里所设置的初始值"通常情况"下是数据类型默认的零值(如0、0L、null、false等)。

解析

将常量池内的符号引用替换为直接引用的过程,也就是得到类或者字段、方法在内存中的指针或者偏移量。

初始化

初始化一个类变量和其他资源,也就是执行类构造器()方法的过程

  1. 当遇到 new 、 getstatic、putstatic或invokestatic 这4条直接码指令时,比如 new 一个类,读取一个静态字段(未被 final 修饰)、或调用一个类的静态方法时。
    • 当jvm执行new指令时会初始化类。即当程序创建一个类的实例对象。
    • 当jvm执行getstatic指令时会初始化类。即程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)。
    • 当jvm执行putstatic指令时会初始化类。即程序给类的静态变量赋值。
    • 当jvm执行invokestatic指令时会初始化类。即程序调用类的静态方法。
  2. 使用 java.lang.reflect 包的方法对类进行反射调用时如Class.forname("..."),newInstance()等等。 ,如果类没初始化,需要触发其初始化。
  3. 初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。
  4. 当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。
  5. MethodHandle和VarHandle可以看作是轻量级的反射调用机制,而要想使用这2个调用, 就必须先使用findStaticVarHandle来初始化要调用的类。
  6. 当一个接口中定义了JDK8新加入的默认方法(被default关键字修饰的接口方法)时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

使用

卸载

卸载类的3个条件:

  1. 该类的所有的实例对象都已被GC,也就是说堆不存在该类的实例对象。
  2. 该类没有在其他任何地方被引用。
  3. 该类的类加载器的实例已被GC。

在JVM生命周期类,由jvm自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。

posted @ 2020-06-01 14:00  西北野狼  阅读(139)  评论(0编辑  收藏  举报