压缩类空间是与元空间并列的独立内存区,仅存储轻量级Klass结构体(约2KB/类),不存完整类元数据;其容量由-XX:CompressedClassSpaceSize显式设定,需配合-XX:+UseCompressedClassPointers启用,且通过JMX或jcmd监控使用率。

压缩类空间(Compressed Class Space)不是元空间的子区域,而是与元空间并列、独立管理的一块本地内存区。它不存储完整类元数据,只存放每个加载类对应的轻量级 Klass 结构体——可理解为“类的索引头”。精准隔离的关键,在于明确它和元空间的分工边界,并通过参数与监控手段实现资源划界。
理解两者职责分离
元空间(Metaspace)负责保存完整的类元数据:方法字节码、常量池、字段/方法签名、注解等;而压缩类空间仅承载每个类一个 Klass* 实例(x64 下典型大小约 2KB)。二者内存物理隔离、容量独立、溢出报错不同:
- java.lang.OutOfMemoryError: Metaspace → 元空间耗尽(如大量动态代理类的字节码本身过大)
- java.lang.OutOfMemoryError: Compressed class space → 压缩类空间耗尽(如 Spring AOP 生成数千个切面类,每个都占一个 Klass)
用参数显式划界,避免默认值干扰
默认情况下,JDK8u60+ 的压缩类空间大小为 1GB(-XX:CompressedClassSpaceSize=1g),但它不受 -XX:MaxMetaspaceSize 影响,也不能靠调大后者缓解前者溢出。若需专属隔离,应主动设置:
- 固定上限:
-XX:CompressedClassSpaceSize=512m(例如限定为 512MB) - 启用压缩指针(必须):
-XX:+UseCompressedClassPointers(否则该区域不分配) - 禁用自动扩容:
-XX:-UseCompressedClassSpace不可用(该 flag 不存在),实际不可关闭,但可通过设小值提前暴露瓶颈
注意:该空间在 JVM 启动时即按设定值 commit,不会动态伸缩,因此设值即“专属配额”。
通过 JMX 和 native memory 精准监控使用率
不能依赖常规 GC 日志或 jstat,因为它们不暴露压缩类空间数据。必须交叉验证:
- JMX 查询 MBean:
java.lang:type=MemoryPool,name=Compressed Class Space,检查Usage.used / Usage.max比值 - 原生内存视图:
jcmd <pid> VM.native_memory summary scale=MB,定位 “Class” 分区 committed 值 - OOM 日志中是否含精确短语:Compressed class space(注意空格和大小写)
在多类加载器场景下强化隔离效果
当应用使用自定义类加载器(如 OSGi、插件化架构、租户隔离网关),每个加载器加载的类都会各自生成 Klass 实例。此时压缩类空间成为天然的“类数量硬闸”:
- 为不同加载器组分配不同 JVM 实例,配合
-XX:CompressedClassSpaceSize分别设限 - 避免共用同一 JVM 加载海量插件类——即使元空间还有余量,Klass 数超限仍会触发 OOM
- 结合
-verbose:class或 JVMTI Agent 统计类加载总数,预估 Klass 占用(≈ 类数 × 2KB)

















