元空间存类的元数据,代码缓存存jit编译后的机器码;前者管理“类是什么”,后者优化“怎么执行快”,二者职责分离、互不替代,均属非堆本地内存。

元空间(Metaspace)和代码缓存(CodeCache)都是JVM的非堆内存区域,但职责完全不同:元空间存的是“类的描述信息”,代码缓存存的是“编译后的机器指令”。它们互不重叠,也不互相替代。
元空间:存放类的元数据
从JDK 8起,永久代(PermGen)被移除,类的元数据(如类名、字段、方法签名、注解、运行时常量池等)改由元空间管理。它使用本地内存(Native Memory),大小默认不限(受系统内存限制),可通过 -XX:MaxMetaspaceSize 控制上限。
- 加载一个类时,类加载器把解析后的结构写入元空间
- 类卸载时(如Web应用热部署、OSGi场景),对应的元空间内存可被回收
- 元空间溢出表现为 java.lang.OutOfMemoryError: Metaspace
- 常见诱因:大量动态生成类(如CGLIB代理、JSON序列化库反复生成类)、未正确卸载ClassLoader
代码缓存:存放JIT编译后的本地代码
当JVM发现某段字节码执行频繁(成为热点代码),JIT编译器会将其编译为平台相关的机器码,并存入CodeCache。这部分内存也属于本地内存,独立于堆,由JVM统一管理。
- 启用JIT后才会持续使用;禁用(-XX:+TieredStopAtLevel=1 或 -Xint)则基本不占用
- 大小由 -XX:InitialCodeCacheSize 和 -XX:ReservedCodeCacheSize 控制,默认通常240MB左右
- 溢出报错是 java.lang.OutOfMemoryError: Compressed class space(注意:该提示有误导性,实际常对应CodeCache满,尤其在开启指针压缩时)或更直接的 CodeCache is full 日志
- 典型场景:高频反射调用、大量Lambda表达式、Groovy/Scala等动态语言生成大量方法
关键区别一目了然
元空间管“是什么”(类定义),代码缓存管“怎么快”(执行优化)。两者都可能因不当使用导致OOM,但监控方式和调优手段不同:
- 查元空间用量:JConsole → “Memory Pool” → Metaspace;或 jstat -gc
看 MC/MU 列 - 查代码缓存状态:jstat -compiler
看 compiled、failed、nmethods、code cache 使用率;VisualVM 的 “MBeans” 中也可查看 CodeCache usage - 调优方向不同:元空间问题多靠限制类加载、清理ClassLoader;CodeCache问题常需调整大小、关闭分层编译(-XX:-TieredCompilation)或排查热点方法膨胀
为什么容易混淆?
因为它们都在堆外、都随JIT和类加载行为变化、都在JConsole里归在“非堆内存”大类下,且错误日志有时表述模糊。但只要记住:一个存“蓝图”,一个存“施工队干完的活”,就很难弄混。










