JVM Class Data Sharing怎样生成类数据归档缩短启动时间怎样完成一个可复用的最小示例
我第一次把 Java 服务的启动优化从“调 JVM 参数”转到 Class Data Sharing(CDS)时,最容易混淆的是:归档不是把整个应用打包成一个更快的 JAR,而是把启动阶段实际加载的类保存为 JVM 可以更快映射的共享数据。先说结论:稳定的 classpath 应用可以用一次试运行生成 classlist,再用 -Xshare:dump 写出 .jsa 归档,启动时通过 -XX:SharedArchiveFile 使用;生产环境优先保留 -Xshare:auto,让不兼容时自动回退。
官方文档:https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html
这篇只讨论 JDK 21 命令行下的 AppCDS 最小闭环:记录类、生成静态归档、指定归档启动,以及 JDK 或启动参数变化后的处理。它不把“启动更快”写成无条件承诺,实际收益仍要用自己的应用基线测量。
先看问题现场:默认 CDS 和应用归档不是一回事
JDK 通常已经带有默认 CDS 归档,-Xshare:auto 会在可用时使用它。这个默认归档主要覆盖 JDK 运行时类;AppCDS 则进一步记录应用实际用到的类。Oracle 文档还提醒,归档类会以优化后的格式存储,归档文件可能比对应 JAR 中的类数据更大,因此应围绕真实启动路径收集,而不是把所有依赖都想当然地塞进去。
我会先把边界固定为三个对象:应用 JAR 和依赖构成的 classpath、试运行输出的 classlist、最终由 JVM 读取的 app.jsa。它们之间的关系如下图所示。

动手验证:先记录一次真正加载过的类
静态 AppCDS 的第一步是让应用在关闭前把加载过的类名写入列表。下面用占位的 app.jar 和主类 com.example.Main 表示命令形态;实际项目要把它们替换成自己的启动入口,并保持后续生成归档时的 classpath 一致。
# 试运行应用,记录启动阶段真正加载过的类
java -Xshare:off \
-XX:DumpLoadedClassList=app.classlist \
-cp "app.jar:lib/*" \
com.example.Main
-Xshare:off 是为了让这次记录不依赖已有共享归档;DumpLoadedClassList 只负责产出类名列表。这个命令本身不是性能结论,也不应把一次试运行当成所有流量路径的完整覆盖。若某些类只在登录、定时任务或特定请求中加载,试运行场景应尽量覆盖这些启动期分支。
定位原因:用 classlist 生成可复用的 .jsa
有了列表后,使用同一套 classpath 调用 -Xshare:dump 生成静态归档。归档文件名可以按 JDK、平台和应用版本分开管理,避免发布时把不匹配的文件误当成通用缓存。
# 使用上一阶段的类列表生成应用级静态归档
java -Xshare:dump \
-XX:SharedClassListFile=app.classlist \
-XX:SharedArchiveFile=app.jsa \
-cp "app.jar:lib/*"
这里最关键的不是参数数量,而是输入关系:app.classlist 描述类,-cp 决定类从哪里解析,app.jsa 是输出文件。把归档复制到另一台机器或换成另一个 JDK 后,不能假设仍然可用;归档要和运行时、类路径以及影响类布局的关键参数一起作为发布产物管理。

修复方案:启动时指定归档,并保留自动回退
归档生成后,应用启动命令增加 -XX:SharedArchiveFile=app.jsa。生产启动一般使用默认的 -Xshare:auto,这样归档因为环境差异不能使用时,JVM 仍可按普通路径启动。-Xshare:on 更适合测试归档是否真的被接受;Oracle 文档明确提示它不应作为生产环境的常规选项。
# 生产倾向:归档可用就使用,不可用时允许 JVM 回退
java -Xshare:auto \
-XX:SharedArchiveFile=app.jsa \
-cp "app.jar:lib/*" \
com.example.Main
# 诊断倾向:要求必须使用共享类数据,不能用于生产兜底
java -Xshare:on \
-XX:SharedArchiveFile=app.jsa \
-cp "app.jar:lib/*" \
com.example.Main
如果只是想减少维护一次静态 classlist,也可以了解 -XX:+AutoCreateSharedArchive 这类自动创建方式;但在发布流水线里,我更愿意先把归档输入、JDK 版本和 classpath 固定下来,再明确决定是否采用自动生成。这样排查启动差异时,能知道归档到底由哪些输入产生。
验证结果:把“归档不可用”当作发布边界处理
当归档没有生效时,优先按下面的顺序对照:第一,生成归档和启动应用是否使用同一 JDK;第二,app.jar:lib/* 是否发生增删或顺序变化;第三,是否修改了会影响 JVM 类布局或启动行为的参数;第四,是否误把 -Xshare:on 带进了生产。修复后重新生成归档,比强行复用旧的 .jsa 更可靠。
| 场景 | 建议 |
|---|---|
| 本地确认归档能否被接受 | 临时使用 -Xshare:on,失败就回到输入匹配问题 |
| 生产部署 | 使用 -Xshare:auto,按版本和运行时保存归档 |
| 依赖或 JDK 发生变化 | 重新试运行、生成 classlist 和 .jsa |
常见问题
只生成 app.jsa,不改启动命令,会自动使用吗?
不会把自定义归档当成无条件自动发现。应在启动参数中通过 -XX:SharedArchiveFile 指定它,并让 -Xshare:auto 负责可用时启用。
AppCDS 能代替应用启动性能基线吗?
不能。它针对类加载和共享数据布局,启动时间还会受到磁盘、容器资源、网络连接和应用初始化逻辑影响。应在相同环境下比较启用前后的多次启动结果。
我对这套最小闭环的判断是:AppCDS 最适合作为“发布产物的一部分”来管理,而不是一条永远不变的 JVM 参数。只要把 JDK、classpath、类列表和归档文件绑定在同一个版本上下文里,遇到归档失效时就能重新生成,而不是盲目追问某个参数为什么突然不生效。
Java record 反射怎样读取 record 组件并保持字段顺序怎样在批处理代码中减少额外分配
- 上一篇
- Java record 反射怎样读取 record 组件并保持字段顺序怎样在批处理代码中减少额外分配
- 下一篇
- sealed class 模式匹配怎样让 switch 在类型层次变化时及时报错怎样完成一个可复用的最小示例
-
- 文章 · java教程 | 22分钟前 |
- JVM Class Data Sharing怎样生成类数据归档缩短启动时间怎样在批处理代码中减少额外分配
- 414浏览 收藏
-
- 文章 · java教程 | 23分钟前 | Java教程 · 类型系统 · java Switch 模式匹配 Java 21 sealed interface sealed class
- sealed class 模式匹配怎样让 switch 在类型层次变化时及时报错怎样完成一个可复用的最小示例
- 284浏览 收藏
-
- 文章 · java教程 | 32分钟前 |
- Java record 反射怎样读取 record 组件并保持字段顺序怎样在批处理代码中减少额外分配
- 479浏览 收藏
-
- 文章 · java教程 | 35分钟前 | 反射 · Java教程 · java 反射 record RecordComponent
- Java record 反射怎样读取 record 组件并保持字段顺序为什么结果为空或不符合预期
- 194浏览 收藏
-
- 文章 · java教程 | 38分钟前 | 反射 · Java · java 反射 字段顺序 record RecordComponent getRecordComponents
- Java record 反射怎样读取 record 组件并保持字段顺序怎样完成一个可复用的最小示例
- 199浏览 收藏
-
- 文章 · java教程 | 40分钟前 |
- Java 虚拟线程 pinned同步块为什么让虚拟线程失去并发优势怎样在批处理代码中减少额外分配
- 200浏览 收藏
-
- 文章 · java教程 | 44分钟前 | 性能排查 · 虚拟线程 · java synchronized reentrantlock 虚拟线程 JFR pinned
- Java 虚拟线程 pinned同步块为什么让虚拟线程失去并发优势为什么结果为空或不符合预期
- 495浏览 收藏
-
- 文章 · java教程 | 47分钟前 |
- Java 虚拟线程 pinned同步块为什么让虚拟线程失去并发优势怎样完成一个可复用的最小示例
- 420浏览 收藏
-
- 文章 · java教程 | 48分钟前 |
- Java Phaser 动态注册参与者并推进阶段同步的实现方法
- 368浏览 收藏
-
- 文章 · java教程 | 52分钟前 |
- CompletableFuture 超时怎样让超时任务停止等待并返回备用值为什么结果为空或不符合预期
- 339浏览 收藏
-
- 文章 · java教程 | 56分钟前 |
- CompletableFuture 超时怎样让超时任务停止等待并返回备用值怎样完成一个可复用的最小示例
- 298浏览 收藏
-
- 文章 · java教程 | 19小时前 | Java · JVM ·
- JVM Class Data Sharing怎样生成类数据归档缩短启动时间为什么结果为空或不符合预期
- 320浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 965次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 966次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1077次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1057次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 888次使用
-
- Go Java 算法之字符串解码示例详解
- 2023-01-07 479浏览
-
- Go Java算法之单词搜索示例详解
- 2022-12-30 337浏览
-
- Gojava算法之括号生成示例详解
- 2023-02-22 128浏览
-
- GoJava算法之累加数示例详解
- 2023-01-07 149浏览
-
- GoJava算法最大单词长度乘积示例详解
- 2023-01-12 202浏览

