类加载机制

110 阅读2分钟

是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

运行时数据区

JVM用来储存加载的类信息、常量、静态变量、编译后的代码等数据。

虚拟机规范中这是一个逻辑区划。具体实现根据不同虚拟机来实现。

如:Oracle的HotSpot在java7中方法区放在永久代,java8放在元数据空间,并且通过GC机制对这个区域进行管理。

类生命周期

问题:class是怎么加载的呢 ?

类加载器

类加载器负责装入类,搜索网络、jar、zip、文件夹、二进制数据、内存等指定位置的类资源。一个java程序运行,最少有三个类加载器实例,负责不同类的加载。

验证问题

  • 查看类对应的加载器

       通过JDK-API进行查看:java.lang.Class.getClassLoader() 

       返回装载类的类加载器

       如果这个类是由bootstrapClassLoader加载的,那么这个方法在这种实现中将返回null

  • JVM如何知道我们的类在何方

      class信息存放在不同的位置,桌面jar、项目bin目录、target目录等

      查看openjdk源代码:sun.misc.Launcher.AppClassLoader

      结论:读取java.class.path配置,指定去哪些地址加载类资源

      验证过程:利用jps、jcmd两个命令

  1. jps查看本机JAVA进程
  2. 查看运行时配置:jcmd + 进程号 + VM.system_properties
  • 类不会重复加载

类的唯一性:同一个类加载器。类名一样,代表是同一个类

识别方式:ClassLoader Instance id + PackageName + ClassName 
验证方式:使用类加载器,对同一个class类的不同版本,进行多次加载,检查是否会加载到最新的代码。

结论不会
  • 类什么时候会被卸载

   满足如下两个条件:

  1.  该Class所有的实例都已经被GC
  2.  加载该类的ClassLoader实例已经被GC

验证方式:jvm启动中增加 -verbose:class参数,输出类加载和卸载的日志信息

  • 双亲委派模型

为了避免重复加载,由下到上逐级委托,由上到下逐级查找。

首先不会自己去尝试加载类,而是把这个请求委派给父加载器去完成;

每一个层次的加载器都是如此,因此所有的类加载请求都会传给上层的启动类加载器。

只有当父加载器反馈自己无法完成该加载请求(该加载器的搜索范围中没有找到对应的类)时,子加载器才会尝试自己去加载

:类加载器之间不存在父类子类的关系,“双亲”是翻译,可以理解为逻辑上定义的上下级关系。