bigywater.tech
Java · 240

CDS 与 AppCDS:把类加载工作提前到归档阶段

类加载是启动时间的大头。CDS 把类的解析结果预先存进归档。这篇用一个真实的 Netty 应用测量默认 CDS 与 AppCDS 的效果、归档的创建方式,以及归档与类路径不一致时的各种表现。

122 → 68 ms
启动时间中位:默认 CDS → AppCDS 动态归档
99%
使用 AppCDS 归档时来自归档的类的比例
不能创建
应用类在目录(而不是 jar)里时动态归档的创建结果

默认 CDS:类从哪里来

实测 · 本机执行输出
  默认(-Xshare:auto)     加载类 1581 个:来自 CDS 归档 937,jrt(JDK 模块文件)139,jar 文件 484,目录 0
  -Xshare:off          加载类 1590 个:来自 CDS 归档 0,jrt(JDK 模块文件)1069,jar 文件 484,目录 0
响应首行:HTTP/1.1 200 OK

AppCDS 动态归档与启动时间

实测 · 本机执行输出
  -Xshare:off                中位 145 ms(最小 144,最大 147)
  默认 CDS(只有 JDK 类)           中位 122 ms(最小 119,最大 128)
  应用类放在目录里(类路径上有一个 classes 目录)时创建动态归档:返回码 1,输出: ["[0.153s][error  ][cds] Error: non-empty directory '<实验目录>'", 'Error occurred during initialization of VM'] ;归档文件是否生成: False
  创建动态 AppCDS 归档:java -XX:ArchiveClassesAtExit=app.jsa(运行一次,退出时写归档),归档文件 5.6 MB,这次运行耗时 205 ms;
  AppCDS 动态归档                中位 68 ms(最小 67,最大 70)
  使用 AppCDS 归档时:加载类 1578 个,来自 CDS 归档 1563 个(99%),其余来自 jar 2 个

归档与类路径不一致

实测 · 本机执行输出
  touch 了类路径上的 netty-codec-http jar 的修改时间之后,-Xshare:auto 运行:返回码 0,时间 120 ms;输出:
    This file is not the one used while building the shared archive file: <m2>/io/netty/netty-codec-http/4.1.115.Final/netty-codec-http-4.1.115.Final.jar
    <m2>/io/netty/netty-codec-http/4.1.115.Final/netty-codec-http-4.1.115.Final.jar timestamp has changed.
    [0.009s][warning][cds,dynamic] Unable to use shared archive. The top archive failed to load: <实验目录>
    响应首行:HTTP/1.1 200 OK
  同样条件 -Xshare:on:返回码 1;输出:
    Unable to map shared spaces
    Error occurred during initialization of VM
    Unable to use shared archive.
  类路径里库的顺序被调换后,-Xshare:auto 运行:返回码 0,来自 CDS 归档的类 937 / 1581;输出: ['shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)', '[0.009s][warning][cds,dynamic] Unable to use shared archive. The top archive failed to load: <实验目录>']

AutoCreateSharedArchive

实测 · 本机执行输出
  第 1 次运行:200 ms,归档文件存在,大小 5.6 MB
  第 2 次运行:70 ms,归档文件存在,大小 5.6 MB
  第 3 次运行:69 ms,归档文件存在,大小 5.6 MB
  第 4 次运行:68 ms,归档文件存在,大小 5.6 MB
  之后再运行 3 次:[69, 70, 68] ms
  touch 了类路径上的一个库 jar 之后,第 1 次运行:154 ms
  touch 了类路径上的一个库 jar 之后,第 2 次运行:123 ms
  touch 了类路径上的一个库 jar 之后,第 3 次运行:120 ms
  这 3 次运行之后,归档文件的修改时间是否变化: False
  删除归档文件后再运行:201 ms,归档文件重新生成:True
  再运行一次:69 ms

分步演示

CDS 与 AppCDS
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS 10 核;应用依赖 Netty 4.1.115(codec-http、handler)
    • 没有验证:静态 AppCDS(-Xshare:dump 与类列表)、归档里的堆对象(archived heap objects)、JDK 21 之外版本的行为、Linux 上的差别、归档大小与类数量的关系、AutoCreateSharedArchive 在 jar 更新后不重新生成的原因(只记录了现象)、容器镜像里分发归档的做法
    京ICP备2026067502号-1京公网安备11010502063487号