CDS

类数据共享 (CDS) 是一种 JVM feature,可帮助减少 Java 应用程序的启动时间和内存占用。

Class Data Sharing (CDS) is a JVM feature that can help reduce the startup time and memory footprint of Java applications.

要使用该功能,应为应用程序的特定类路径创建 CDS 存档。Spring 框架提供一个挂接点来简化存档的创建。存档可用后,用户应通过 JVM 标志选择使用它。

To use this feature, a CDS archive should be created for the particular classpath of the application. The Spring Framework provides a hook-point to ease the creation of the archive. Once the archive is available, users should opt in to use it via a JVM flag.

Creating the CDS Archive

可以在应用程序退出时创建应用程序的 CDS 存档。Spring 框架提供一种操作模式,即一旦 ApplicationContext 刷新,进程可以自动退出。在此模式下,所有非延迟初始化单例都已实例化,并且已调用 InitializingBean#afterPropertiesSet 回调;但生命周期尚未开始,并且尚未发布 ContextRefreshedEvent

A CDS archive for an application can be created when the application exits. The Spring Framework provides a mode of operation where the process can exit automatically once the ApplicationContext has refreshed. In this mode, all non-lazy initialized singletons have been instantiated, and InitializingBean#afterPropertiesSet callbacks have been invoked; but the lifecycle has not started, and the ContextRefreshedEvent has not yet been published.

要创建存档,必须指定两个附加 JVM 标志:

To create the archive, two additional JVM flags must be specified:

  • -XX:ArchiveClassesAtExit=application.jsa: creates the CDS archive on exit

  • -Dspring.context.exit=onRefresh: starts and then immediately exits your Spring application as described above

要创建 CDS 存档,JDK/JRE 必须具有基础镜像。如果你将上述标志添加到启动脚本中,可能会收到如下警告:

To create a CDS archive, your JDK/JRE must have a base image. If you add the flags above to your startup script, you may get a warning that looks like this:

-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info.

基础 CDS 存档通常开箱即用,但如果需要,也可以通过发出以下命令进行创建:

The base CDS archive is usually provided out-of-the-box, but can also be created if needed by issuing the following command:

$ java -Xshare:dump

Using the Archive

存档可用后,假设工作目录中有一个 application.jsa 文件,将 -XX:SharedArchiveFile=application.jsa 添加到启动脚本中以使用它。

Once the archive is available, add -XX:SharedArchiveFile=application.jsa to your startup script to use it, assuming an application.jsa file in the working directory.

若要检查 CDS 缓存是否有效,可以(仅用于测试目的,不得用于生产中)使用 -Xshare:on,如果无法启用 CDS,它会打印一条错误消息并退出。

To check if the CDS cache is effective, you can use (for testing purposes only, not in production) -Xshare:on which prints an error message and exits if CDS can’t be enabled.

若要了解缓存的有效程度,可以通过添加额外属性 -Xlog:class+load:file=cds.log 启用类加载日志。这会为每次尝试加载类及其源创建 cds.log。从缓存加载的类应具有“共享对象文件”源,如下面的示例所示:

To figure out how effective the cache is, you can enable class loading logs by adding an extra attribute: -Xlog:class+load:file=cds.log. This creates a cds.log with every attempt to load a class and its source. Classes that are loaded from the cache should have a "shared objects file" source, as shown in the following example:

[0.064s][info][class,load] org.springframework.core.env.EnvironmentCapable source: shared objects file (top)
[0.064s][info][class,load] org.springframework.beans.factory.BeanFactory source: shared objects file (top)
[0.064s][info][class,load] org.springframework.beans.factory.ListableBeanFactory source: shared objects file (top)
[0.064s][info][class,load] org.springframework.beans.factory.HierarchicalBeanFactory source: shared objects file (top)
[0.065s][info][class,load] org.springframework.context.MessageSource source: shared objects file (top)

如果无法启用 CDS,或者有许多类没有从缓存中加载,请确保在创建和使用存档时满足以下条件:

If CDS can’t be enabled or if you have a large number of classes that are not loaded from the cache, make sure that the following conditions are fulfilled when creating and using the archive:

  • The very same JVM must used.

  • The classpath must be specified as a list of JARs, and avoid the usage of directories and * wildcard characters.

  • The timestamps of the JARs must be preserved.

  • When using the archive, the classpath must be the same than the one used to create the archive, in the same order. Additional JARs or directories can be specified at the end (but won’t be cached).