登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

JVM Class Data Sharing怎样生成类数据归档缩短启动时间为什么结果为空或不符合预期

来源:17golang原创

时间:2026-11-09 10:02:23 320浏览 收藏

JVM Class Data Sharing(CDS)归档不是把整个应用打包成一个更快的 JAR,而是把一次试运行中真正加载的类整理成 JVM 可直接映射的共享数据。要生成能命中的归档,关键是“试运行生成类表、用相同类路径 dump、启动时显式加载、再看 class load 日志”这四步。类表为空通常说明试运行没有成功走到应用入口;归档不生效则优先检查 JAR 是否被替换、类路径是否改变,以及是否带了会禁用 CDS 的模块参数。

官方文档:https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html

要点速览
  • 试运行必须使用 -Xshare:off -XX:DumpLoadedClassList,先得到真实类表。
  • -Xshare:dump 时的类路径应与运行时相同或是运行时类路径的前缀,类路径中的 JAR 不能在 dump 后被修改。
  • 用 -Xlog:class+load 看见 source: shared objects file,才说明目标类命中了归档。

先用一次试运行生成 classlist

下面的示例假定应用入口是 com.example.Main,依赖都放在 lib/ 目录。类路径只写 JAR,不要直接放非空目录;这样得到的类表更接近后续可复用的归档边界。

# 关闭默认 CDS,避免试运行结果混入已有共享归档
java -Xshare:off \
  -XX:DumpLoadedClassList=app.classlist \
  -cp "app.jar:lib/*" \
  com.example.Main

# 先确认类表确实生成,并且包含应用自己的类名
wc -l app.classlist
grep 'com/example/Main' app.classlist

如果 app.classlist 为零字节,先处理应用启动失败、入口类拼写、依赖缺失或进程提前退出。不要直接进入 dump 阶段,因为空类表只能得到没有应用类的归档。

JVM Class Data Sharing 从应用试运行类表到 JSA 归档的输入输出关系说明图
图1:JVM CDS 类表、类路径与 JSA 归档的关系说明图,不是运行截图。

用同一类路径生成并加载 JSA

有了类表后,用 -Xshare:dump 创建归档。dump 时的类路径必须覆盖类表中类的来源;运行时类路径可以是它的相同路径或前缀,但不要为了“精简”随意换 JAR 顺序。

# 使用与试运行一致的JAR类路径生成静态CDS归档
java -Xshare:dump \
  -XX:SharedArchiveFile=app.jsa \
  -XX:SharedClassListFile=app.classlist \
  -cp "app.jar:lib/*"

# 启动时加载自定义归档,并输出类加载来源
java -XX:SharedArchiveFile=app.jsa \
  -Xlog:class+load \
  -cp "app.jar:lib/*" \
  com.example.Main

日志中若出现 com.example.Main source: shared objects file,说明这个类从归档读取。若显示为 JAR 路径,只能说明该类没有命中;不必把整次启动误判为 CDS 完全失效。

现象优先检查处理方向
classlist 为空入口、依赖、启动退出码先让试运行完整走到业务入口
JSA 生成但类仍来自 JAR类路径顺序、JAR 是否变化恢复 dump 与运行时的一致路径
启动直接报 CDS 不可用JDK 构建、特殊 VM 参数先用默认配置复现,再逐项加入参数

结果为空或归档被忽略时的边界排查

CDS 归档绑定的不只是类名,还绑定类的来源和 JVM 构建环境。dump 后替换 app.jar、改变依赖版本、调整类路径,都会让相应类退回动态加载。--patch-module、--limit-modules 和 --upgrade-module-path 等参数也可能禁用 CDS;排查时先去掉它们,再用最小命令确认归档命中。

如果目标是减少多进程的常驻内存,可以继续使用同一归档;如果只是想省去手工试运行,JDK 21 也支持 -XX:+AutoCreateSharedArchive。但自动归档同样要求后续启动使用同一 JDK 构建和相同命令行,不能把它当成任意环境通用的缓存文件。

JVM CDS 命中诊断中类路径、JDK 构建和日志来源三类判断关系说明图
图2:从类路径、JDK 构建到 shared objects file 日志的命中诊断结构图,不是运行截图。

常见问题

为什么生成了 app.jsa,启动却没有明显变快?

CDS 主要减少类元数据准备和部分启动工作,收益会受应用规模、磁盘和启动阶段占比影响。先用日志确认命中,再用多次冷启动对比,别只看一次耗时。

classlist 里没有业务类怎么办?

通常是入口没有真正执行到业务代码,或试运行使用了错误的类路径。先检查退出码和应用日志,再重新生成类表。

能把 JSA 文件复制到另一台机器吗?

不应把它当作跨 JDK、跨构建、跨应用版本的通用缓存。至少保持 JDK 构建、类路径和相关 JAR 内容一致,并重新用类加载日志确认。

实际落地时,先把“类表是否有内容”和“目标类是否来自 shared objects file”作为两个独立检查点。前者验证采集成功,后者验证归档真正参与启动,定位会比只看 JSA 文件是否存在更快。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>