Skip to content

JEP 350: Dynamic CDS Archives | 动态 CDS 归档

摘要

应用程序类数据共享 扩展到允许在 Java 应用程序执行结束时动态归档类。归档的类将包括所有已加载的应用程序类和库类,这些类不在默认的、基础层的 CDS 归档中。

目标

  • 提高应用程序类数据共享(AppCDS)的可用性。消除用户为每个应用程序创建类列表进行试运行的需求。

  • 使用类列表通过 -Xshare:dump 选项启用的静态归档应继续工作。这包括内置类加载器和用户定义类加载器的类。

非目标

  • 只有应用程序执行期间加载的类才会被归档。如果某个类存在于给定的 JAR 文件中但在执行期间没有被加载,那么它不会被归档。

  • 应用程序执行期间创建的 Java 堆对象不会被动态归档。

  • 如果应用程序突然退出(例如崩溃),则不会进行动态归档。

动机

在 HotSpot 中使用 AppCDS 归档应用程序类相对于 默认 CDS 归档 提供了额外的启动时间和内存优势。然而,目前要使用 AppCDS 为 Java 应用程序服务,需要遵循一个三步程序:

  1. 进行一次或多次试运行以创建类列表
  2. 使用创建的类列表转储归档
  3. 使用归档运行

此外,这个程序仅适用于仅使用内置类加载器的应用程序。HotSpot 中支持对由用户定义的类加载器加载的类进行归档的实验性支持,但其使用起来并不方便。

通过命令行选项启用的动态归档将通过消除试运行(即上述步骤 1)来简化 AppCDS 的使用,并且将有效且统一地支持内置类加载器和用户定义的类加载器。

这个 JEP 的一个后续增强可以在应用程序的第一次运行时自动进行归档生成。这将消除显式创建归档的步骤(即上述步骤 2)。这样,CDS/AppCDS 的使用可以完全透明和自动化。

描述

支持的归档配置

在运行时将支持以下配置:

  • 静态基础归档(默认 CDS 归档)+ 动态归档 — 当两个归档都成功映射时
  • 仅静态基础归档 — 当动态归档无法映射时

动态归档当前需要默认 CDS 归档作为基础归档。如果基础层归档在运行时无法映射和使用,则顶层动态归档将自动禁用。

退出时归档类

如果指定了 -XX:ArchiveClassesAtExit 选项,则应用程序退出时会动态创建一个共享归档。

动态生成的归档是在与正在运行的 JDK 映像一起打包的默认系统归档之上创建的。每个应用程序都会生成一个单独的顶层归档文件。用户可以将动态归档的文件名指定为 -XX:ArchiveClassesAtExit 选项的参数。例如,以下命令将创建 hello.jsa

bash
% bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello

要使用此动态归档运行相同的应用程序:

bash
% bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

基础层依赖

动态创建的顶层归档依赖于基础层归档(即,它包含指向基础层数据的指针),因此基础归档头部和所有共享空间的 CRC 值都被记录在顶层中。

在运行时,当动态归档被映射时,所有记录的 CRC 值都会与当前映射的基础归档 CRC 值进行比较。如果任何 CRC 值不匹配,则动态归档将被禁用,而不影响当前映射的基础归档的使用。

使用 CRC 值来检查基础归档依赖比使用文件名、大小和时间戳检查更为健壮。

复制和重新定位类元数据

所有加载的应用程序类和库类(排除包含在基础层中的类)都在顶层中动态归档。目前,复制和重新定位类元数据是在应用程序执行结束且虚拟机退出之前完成的。归档的数据会被清理以删除任何不可共享的信息。

对于用户定义的类加载器,JVM 需要在类加载器及其加载的类被卸载之前进行额外的复制操作。缓冲的数据会与其余动态归档的类元数据一起复制到共享空间中。

动态归档中的共享空间

动态归档的布局与现有的静态归档类似。元数据被分为以下四个空间。不需要“md”空间。

  • rw:可读 / 可写数据
  • ro:只读数据
  • mc:跳板代码(Trampoline)

这些共享空间在运行时单独映射。“ro”空间被映射为只读,以支持跨进程共享。

内存节省

当你在同一主机上运行多个相关进程时,通过使用两级归档可以提高内存共享。例如,当你有以下这些程序,它们共享相同的一组库时:

2 个进程使用“-cp:lib.jar:foo.jar FooApp”运行

4 个进程使用“-cp:lib.jar:bar.jar BarApp”运行

你可以仅为 lib.jar 中的类(以及这些应用使用的其他系统类)创建一个静态归档(使用类列表)。然后,为“foo”应用创建一个动态归档,为“bar”应用创建另一个动态归档。

通过这种方式,静态归档可以在所有 6 个进程之间共享,而动态归档可以在运行相同程序的进程之间共享。

替代方案

在动态归档期间,可以在加载请求的类之后立即复制和重新定位类元数据。在虚拟机退出之前,通过将数据重新定位到归档空间,可以在应用程序执行结束时将类元数据重新定位到归档空间。

测试

  • 应执行所有现有的 CDS 和 AppCDS 测试,以确保从类列表进行的静态归档能够正常工作。
  • 应开发新的测试来测试使用内置类加载器和用户定义类加载器的动态归档。