【Java核心-进阶】类加载

Java类加载的三个阶段

Loading, Linking, and Initializing

加载(Loading)

将Java字节码数据读取到JVM中,并映射为 Class 对象。

数据源可以是 jar文件、class文件或网络数据源。

用户可以实现自己的类加载器来自定义加载过程。

链接(Linking)

把原始的类定义信息平滑地转化入JVM。

分为三个子步骤:

验证(Verification)

这是JVM安全的重要保障。

JVM会核验字节信息是否符合 Java 虚拟机规范,防止恶意信息或不合规的信息危害JVM运行。

验证阶段可能会触发更多 class 的加载。

准备(Preparation)

创建类或接口中的静态变量,并初始化静态变量的初始值。

此步骤侧重于分配内存空间,不会去执行更进一步的JVM指令;与后续的“初始化”不同。

解析(Resolution)

将常量池中的 符号引用(Symbolic Reference)替换为直接引用。

初始化(Initialization)

真正执行类初始化的代码逻辑,包括 对静态字段进行赋值、执行静态代码块。

这些代码逻辑事先由编译器在编译阶段整理好。父类型的初始化 优先于 当前类型。

Parent Delegation Model(“双亲委派模型”)

其实翻译为“双亲”很容易误导中文读者。(在学习“树”的数据结构时,我们会把“parent node”翻译为“父节点”)

此处的委派模型指:当一个ClassLoader需要加载一个类时,会尝试将该任务委托给它的 父ClassLoader,除非父ClassLoader找不到目标资源。

目的:这种委派模型的目的是为了避免重复加载Java类型。

这体现了类加载机制的“可见性”和“单一性”。

可见性:子ClassLoader可见到父ClassLoader加载的类型(反之不能)。

单一性:子ClassLoader不会加载父ClassLoader已经加载过的类型。

但是“邻居”ClassLoader之间,同一类型仍然可以被加载多次;因为它们互相不可见。

Java 8 及以前的 类加载器

三个内建的 类加载器

Bootstrap Class-Loader(启动类加载器)

加载 jre/lib 目录下的 jar包。如,rt.jar。

Extension Class-Loader(扩展类加载器)

加载 jre/lib/ext 目录下的 jar包。

Application Class-Loader(应用类加载器)

加载 classpath 下的资源

Java 9 的类加载器

Jigsaw 项目为 Java 9 引入了 Java平台模块化系统(JPMS)。Java SE的源码被划分为一系列模块,类加载器也发生了非常大的变化。

如,扩展类加载器被重命名为“平台类加载器”(Platform Class-Loader);rt.jar 被移除,JDK核心类库被存储在 jimage 文件中。

新增的 Layer 抽象可以更方便地实现类似容器的逻辑。

内建类的加载器都在 BootLayer 中;

其它Layer内部有自定义的类加载器;

不同版本模块可以同时工作在不同的 Layer中。

自定义类加载器

使用场景

绝大多数应用都不需要实现自定义的类加载器。一般在以下场景中会用到自定义类加载器:

  • 实现“进程内隔离”。

    类加载器作用于不同的命名空间,它可以提供类似 容器/模块化 的效果。

    如,两个模块分别依赖于某个类库的不同版本,让这两个模块分别被不同的“容器”加载就可以互不干扰。

    Java EEOSGIJPMS 等框架都有这种机制

  • 从不同的数据源获取类定义信息。

    如,应用需要从网络数据源获取类信息,而不是本地文件系统

  • 需要自己操作字节码,动态修改或生成类型。

实现方式

大致步骤:

通过指定的名称,找到其二进制实现(字节码),或修改/生成字节码。自定义类加载器一般就是在这做“定制”

创建 Class 对象,并完成类加载过程。通过  ClassLoader.defineClass 方法将二进制信息转换为 Class 对象。

扩展:《Class Loaders in Java

加快java类信息加载的技术

Java类的加载、解释、编译都需要时间,这会明显导致Java应用启动变慢。

类加载器获得的类信息是字节码,它与平台无关,具体用于执行时还需要解释/编译。

AOT(Ahead-of-Time Compilation)

这项技术是提前把Java Class提前编译为本地代码(native code),以加速Java应用的启动时间。

目前还只是试验性的特性,局限性比较大。

AppCDS(Application Class-Data Sharing)

这项技术可以将Java Class信息存储在文件系统中,作为 Shared Archive。

JVM会通过内存映射技术映射到相应的地址空间,免除类加载、解析等开销,加速启动,同时也可以减少内存占用(footprint)。

局限性:如果存在大量运行时动态类加载,此技术的帮助会很有限

发布了219 篇原创文章 · 获赞 3 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/hchaoh/article/details/103906301
今日推荐