JVM -- 类加载相关

0、前言

以下都是基于 HotSpot 虚拟机

 

1、JVM 的整体结构

概览图:

        

 

 

详细图:

 

 

运行时数据区详细解释:

 

 

JDK8 之后把方法区划成了元数据区域,其实元数据+JIT编译产物都可以称作非堆区

 

 

 

 

 

 

 

 

2、类的加载过程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。它们的顺序如下图所示:

具体每一步都干了什么 => 参考链接

其中注意

1)链接(link)中的 准备(prepare)阶段会给类变量(用static修饰的)赋默认值,比如 int 的默认值是 0

2)加载(load)只负责将类的二进制信息加载进来,不负责其他。

3)类的初始化时机有触发条件,如下主动使用的情况

 

 

 

 

 结合 2)和 3)于是就有了Class.forName 和 ClassLoader.load 的区别,参考此链接

 

 

 

 

 

 3、类加载过程的类加载器

 

 

 

 1) Bootstrap Class Loader

 

2) Extension Class Loader

 

 

 3) Application Class Loader

 

 

 

 BTW:

JVM中如何判断两个Class对象是否是同一个类需要满足两个条件

1)类的完整类名必须完全一致,包括包名

2)加载类的类加载器必须也是相同的!

也就是说,即便是同一个 Class 文件出来的类信息,只要使用的加载器不一样,那在 JVM 中就不能视为同一个类

 

 

 

 

 

4、关于 ClassLoader 类

 

 

 

 

注:点开 sun.misc.Launcher 源码可以看到 ExtClassLoader 和 AppClassLoader 是其内部类,而 Launcher 是由 BootstrapClassLoader 加载。详情可以参考此链接

在代码中可以有三种方式来获取 ClassLoader 类。详情参考此链接

 

 

 

 

 

 

 

 5、双亲委派机制

 

 

 

好处 :这个机制保护了基础类不被蓄意 "破坏",例如类java.lang.Object,它存在在rt.jar,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱。因此,如果开发者尝试编写一个与rt.jar类库中重名的Java类可以正常编译,但是永远无法被加载运行。

特殊情况:有时候父加载器需要子加载器对某些类进行加载,需要破坏原本的 "向上" 传递的规则 ,于是就有了 Thread.currentThread().getContextClassLoader() 具体参考此链接

 

posted @ 2020-03-16 23:59  qwerity  阅读(150)  评论(0编辑  收藏  举报