AppCDS本质是通过mmap()映射预处理的类元数据二进制归档(如app.jsa),跳过解析、验证、链接等重复步骤;需显式指定-XX:SharedArchiveFile和classlist以确保类稳定性与环境匹配,校验失败则静默降级。

类数据共享(CDS)本质是内存映射的预处理元数据缓存
CDS 不是“类加载加速器”,而是把解析、验证、链接后的类元数据(klass、method、常量池等)序列化为平台相关二进制块,写入一个归档文件(如 classes.jsa),后续 JVM 启动时用 mmap() 直接映射到只读内存段。它跳过了从 rt.jar 或 jmods 逐个读取、字节码校验、符号解析等重复步骤。
为什么 AppCDS 要求显式指定 -XX:SharedArchiveFile 和 classlist
AppCDS 共享的是应用类路径(-cp)下的类,但 JVM 无法自动判断哪些类稳定、可安全共享:类可能依赖运行时动态生成字节码(如 CGLIB)、使用不兼容的 ClassLoader、或含静态初始化块副作用。所以必须通过两步约束:
- 先用
java -Xshare:dump -XX:SharedArchiveFile=app.jsa -XX:ClassList=app.lst -cp myapp.jar MyApp生成 classlist(或用-XX:+UseAppCDS+-XX:SharedArchiveFile配合已存在的 base JSA) - 再启动时用
-XX:SharedArchiveFile=app.jsa -Xshare:on显式启用——JVM 会校验归档中每个类的 CRC、签名、加载器类型是否匹配当前运行环境 - 若校验失败(比如 jar 被修改、JDK 小版本升级),JVM 自动退回到常规加载,并打印警告:
Unable to use shared archive
Dynamic CDS(JEP 350)如何绕过 classlist 手动维护
Dynamic CDS 的核心变化是:不再靠静态 classlist 描述“哪些类该归档”,而是在 JVM 正常退出时,把本次运行中实际加载且满足条件的类(非匿名、非 Lambda、非 Unsafe.defineAnonymousClass 生成)自动 dump 成 top-level JSA。这带来两个关键行为差异:
- 无需提前构造
app.lst,适合 CI/CD 流水线中构建即归档 - 支持部分自定义
ClassLoader(如 Spring Boot 的LaunchedURLClassLoader),但要求其defineClass流程不破坏类结构一致性 - 必须配合 base JSA 使用(如
$JAVA_HOME/lib/server/classes.jsa),top JSA 只存增量部分;启动时 JVM 同时映射 base + top,按需合并
常见失效场景和排查线索
CDS 失效往往静默降级,不会报错,但启动时间没变快。真正起作用的信号只有 JVM 启动日志里的几行:
- 成功启用:
Loaded shared classes from shared archive.或Using shared archive: /path/to/app.jsa - classlist 不匹配:
Preload list contains invalid class: com.example.MyService - JDK 版本漂移:
Archive requires version xx, but version yy is running - GC 参数冲突:启用
-XX:+UseG1GC时若 base JSA 是用默认 GC 生成的,可能触发重 dump 或拒绝加载 - 容器环境注意:
/proc/sys/vm/max_map_count过低会导致 mmap 失败,表现为Failed to map shared archive
最易被忽略的是 classlist 中类名格式:必须是内部形式(java/lang/String),不能带 .class 后缀或斜杠反斜杠混用;另外 Spring Boot fat-jar 中的嵌套路径(BOOT-INF/classes/)需解压后生成 classlist,否则找不到类。


















