构建时生成Java CDS类列表 避免K8s Pod重启及归档错误
构建时手动生成Java CDS类列表跳过K8s Pod重启的问题解决
问题背景
你在Kubernetes部署的Java应用中使用CDS归档优化启动速度,之前通过修改Java opts(-XX:+ArchiveClassesAtExit)生成类列表并创建归档,成功节省约60秒启动时间。现在希望在构建阶段手动生成类列表,避免生成类列表所需的Pod重启步骤,但遍历项目所有Jar生成类列表后,创建归档时出现以下错误:
[error][cds,heap] Cannot archive the sub-graph referenced from [Ljava.util.concurrent.ConcurrentHashMap$Node; object (0x00000000ad07fd00) size 1048592, skipped. [error][cds] An error has occurred while writing the shared archive file.
报错原因
手动遍历Jar生成的类列表包含了不适合CDS归档的类/对象引用:
[Ljava.util.concurrent.ConcurrentHashMap$Node;是ConcurrentHashMap的内部数组类,属于运行时动态创建的大对象,CDS无法归档这类对象的引用子图。- Jar中存在大量启动阶段不会加载的类,手动全量收集的列表包含了这些类,导致JVM在归档时尝试处理无法被归档的运行时对象。
可行解决方案
1. 优化手动类列表生成逻辑,只收集启动阶段加载的类
- 先通过JVM启动日志筛选实际加载的类:添加
-verbose:class参数启动应用,输出所有加载的类,以此为基础生成类列表,剔除运行时动态创建的数组类(如[Lxxx;格式的类名)。 - 用工具分析启动类加载:比如
jcmd <pid> VM.class_hierarchy或Java Flight Recorder,捕获启动阶段的类加载数据,生成精准的类列表。
2. 构建阶段模拟启动生成归档(推荐)
不用手动遍历Jar,直接在CI/CD构建阶段启动一次应用生成归档,既避免生产Pod重启,又保证类列表的准确性:
# 在构建容器中启动应用,指定生成归档文件 java -XX:+ArchiveClassesAtExit -XX:SharedArchiveFile=app-cds.jsa -jar your-app.jar & # 等待应用启动完成(可通过curl检测健康接口替代sleep) sleep 30 # 停止应用,此时归档文件已生成 pkill -f your-app.jar # 将归档文件打包到最终镜像的指定路径(比如/opt/app/)
这种方式由JVM自主筛选适合归档的类,不会包含无法归档的大对象引用,可靠性远高于手动遍历。
3. 调整CDS参数跳过无法归档的对象
如果坚持手动生成类列表,可添加参数让JVM跳过报错的对象:
java -XX:SharedArchiveFile=your-archive.jsa -XX:+UseSharedSpaces -XX:SkipUnsupportedClassesInArchive=true -jar your-app.jar
但此方法可能损失部分CDS优化效果,需测试验证启动速度变化。
内容的提问来源于stack exchange,提问作者curious_lak
相关产品推荐
相关产品推荐

