最新版JDK15下的JVM类加载器原理详解(上)

简介: 最新版JDK15下的JVM类加载器原理详解(上)

类加载器是如何定位具体的类文件并读取的呢?

1 类加载器

在类加载器家族中存在着类似人类社会的权力等级制度:

1.1 Bootstrap

由C/C++实现,启动类加载器,属最高层,JVM启动时创建,通常由与os相关的本地代码实现,是最根基的类加载器。

JDK8 时

需要注意的是,Bootstrap ClassLoader智慧加载特定名称的类库,比如rt.jar.这意味我们自定义的jar扔到<JAVA_HOME>\jre\lib也不会被加载.


负责将<JAVA_ HOME>/jre/lib或- Xbootclasspath参数指定的路径中的,且是虚拟机识别的类库加载到内存中(按照名字识别,比如rt.jar,对于不能识别的文件不予装载),比如:

Object

System

String

Java运行时的rt.jar等jar包

系统属性sun.boot.class.path指定的目录中特定名称的jar包

在JVM启动时,通过Bootstrap ClassLoader加载rt.jar,并初始化sun.misc.Launcher从而创建Extension ClassLoader和Application ClassLoader的实例。

查看Bootstrap ClassLoader到底初始化了那些类库:

URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
       for (URL urL : urLs) {
           System.out.println(urL.toExternalForm());
       }

JDK9 后

负责加载启动时的基础模块类,比如:

  • java.base
  • java.management
  • java.xml

1.2 Platform ClassLoader

JDK8 时Extension ClassLoader

只有一个实例,由sun.misc.Launcher$ExtClassLoader实现:


负责加载<JAVA_HOME>\lib\ext或java.ext.dirs系统变量指定的路径中的所有类库

加载一些扩展的系统类,比如XML、加密、压缩相关的功能类等

JDK9时替换为平台类加载器

加载一些平台相关的模块,比如java.scriptingjava.compiler*java.corba*

那为何 9 时废除替换了呢?

JDK8 的主要加载 jre lib 的ext,扩展 jar 包时使用,这样操作并不推荐,所以废除。而 JDK9 有了模块化,更无需这种扩展加载器。

1.3 Application ClassLoader

只有一个实例,由sun.misc.Launcher$AppClassLoader实现。

JDK8 时

负责加载系统环境变量ClassPath或者系统属性java.class.path指定目录下的所有类库。

如果应用程序中没有定义自己的加载器,则该加载器也就是默认的类加载器。该加载器可以通过java.lang.ClassLoader.getSystemClassLoader获取。

JDK9 后

应用程序类加载器,用于加载应用级别的模块,比如:

  • jdk.compiler
  • jdk.jartool
  • jdk.jshell
  • 5.png
  • classpath路径中的所有类库

第二、三层类加载器为Java语言实现,用户也可以

1.4 自定义类加载器

用户自定义的加载器,是java.lang.ClassLoader的子类,用户可以定制类的加载方式;只不过自定义类加载器其加载的顺序是在所有系统类加载器的最后。

1.5 Thread Context ClassLoader

每个线程都有一个类加载器(jdk 1.2后引入),称之为Thread Context ClassLoader,如果线程创建时没有设置,则默认从父线程中继承一个,如果在应用全局内都没有设置,则所有Thread Context ClassLoader为Application ClassLoader.可通过Thread.currentThread().setContextClassLoader(ClassLoader)来设置,通过Thread.currentThread().getContextClassLoader()来获取.


线程上下文加载器有什么用?

该类加载器容许父类加载器通过子类加载器加载所需要的类库,也就是打破了我们下文所说的双亲委派模型。

这有什么好处呢?

利用线程上下文加载器,我们能够实现所有的代码热替换,热部署,Android中的热更新原理也是借鉴如此。

2 验证类加载器

2.1 查看本地类加载器

6.png

在JDK8环境中,执行结果如下

7.png

AppClassLoader的Parent为Bootstrap,它是通过C/C++实现的,并不存在于JVM体系内,所以输出为 null。

类加载器的特点

类加载器并不需要等到某个类"首次主动使用”的时候才加载它,JVM规范允许类加载器在预料到某个类将要被使用的时候就预先加载它。

Java程序不能直接引用启动类加载器,直接设置classLoader为null,默认就使用启动类加载器

如果在加载的时候.class文件缺失,会在该类首次主动使用时通知LinkageError错误,如果一直没有被使用,就不会报错

如果没有指定父加载器,默认就是启动加载器

每个类加载器都有自己的命名空间,命名空间由该加载器及其所有父加载器所加载的类构成。不同的命名空间,可以出现类的全路径名相同的情况

运行时包由同一个类加载器的类构成,决定两个类是否属于同一个运行时包,不仅要看全路径名是否一样,还要看定义类加载器是否相同。只有属于同一个运行时包的类才能实现相互包内可见

image.png

低层次的当前类加载器,不能覆盖更高层次类加载器已经加载的类

如果低层次的类加载器想加载一个未知类,要非常礼貌地向上逐级询问:“请问,这个类已经加载了吗?”

被询问的高层次类加载器会自问两个问题


我是否已加载过此类

如果没有,是否可以加载此类

只有当所有高层次类加载器在两个问题的答案均为“否”时,才可以让当前类加载器加载这个未知类

左侧绿色箭头向上逐级询问是否已加载此类,直至Bootstrap ClassLoader,然后向下逐级尝试是否能够加载此类,如果都加载不了,则通知发起加载请求的当前类加载器,准予加载

在右侧的三个小标签里,列举了此层类加载器主要加载的代表性类库,事实上不止于此


通过如下代码可以查看Bootstrap 所有已加载类库

9.png

执行结果

10.png

目录
相关文章
|
16小时前
|
存储 监控 算法
JVM工作原理与实战(四十一):ShenandoahGC原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了ShenandoahGC、ShenandoahGC 1.0版本、ShenandoahGC 2.0版本、ShenandoahGC执行流程等内容。
|
16小时前
|
监控 算法 安全
JVM工作原理与实战(三十九):G1垃圾回收器原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了G1垃圾回收器执行流程、年轻代回收原理、卡表(Card Table)、记忆集的生成流程、年轻代回收的详细步骤、混合回收的步骤、初始标记、并发标记、SATB、转移等内容。
|
17小时前
|
监控 安全 Java
JVM工作原理与实战(三十八):JIT即时编译器原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JIT即时编译器、HotSpot中的JIT编译器、JIT优化技术、JIT优化建议等内容。
|
1天前
|
Arthas 人工智能 监控
JVM工作原理与实战(三十五):性能调优
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了性能调优、性能调优案例等内容。
13 1
|
1天前
|
存储 缓存 监控
JVM工作原理与实战(三十四):解决GC问题的方法
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了常见的垃圾回收(GC)模式、解决GC问题的方法(优化基础JVM参数、减少对象产生、更换垃圾回收器、优化垃圾回收器的参数)等内容。
|
1天前
|
Prometheus 监控 Cloud Native
JVM工作原理与实战(三十三):监控GC过程的工具
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了jstat工具、VisualVM插件、Prometheus + Grafana、GC日志等内容。
11 0
|
1天前
|
监控 负载均衡 算法
JVM工作原理与实战(三十二):GC调优
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了GC调优、GC调优的核心指标等内容。
|
1天前
|
Arthas 监控 Java
JVM工作原理与实战(三十一):诊断内存泄漏的原因
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了诊断内存溢出的原因、MAT内存泄漏检测的原理等内容。
|
1天前
|
存储 Arthas 监控
JVM工作原理与实战(三十):堆内存状况的对比分析
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了堆内存状况的对比分析、产生内存溢出的原因等内容。
|
1天前
|
Arthas Prometheus 监控
JVM工作原理与实战(二十九):监控内存泄漏的工具
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了解决内存溢出的步骤、Top命令、VisualVM、Arthas、Prometheus + Grafana等内容。