java 8起元空间(metaspace)替代永久代(permgen),核心差异在于:metaspace使用本地内存、动态分配,metaspacesize是gc触发阈值而非预分配大小,默认无上限,而permgen为固定大小堆外内存,超限即抛oom;生产建议设metaspacesize与maxmetaspacesize相等以控波动。

Java 8 之前用 PermSize 控制永久代(PermGen)大小,Java 8 起改用 MetaspaceSize 管理元空间(Metaspace),二者核心差异不在“名字”,而在内存机制、默认行为和调优逻辑。
内存归属与分配方式不同
PermGen 是 JVM 堆外但受 JVM 管控的一块固定区域,启动时就按 -XX:PermSize 分配连续内存;而 Metaspace 直接使用本地内存(Native Memory),-XX:MetaspaceSize 只是触发 Full GC 的阈值,并非预分配大小。实际内存按需向操作系统申请,直到达到 -XX:MaxMetaspaceSize 上限或系统内存耗尽。
默认值与动态行为差异明显
- JDK 7 及以前:
-XX:PermSize默认约 20.75MB(64位),-XX:MaxPermSize默认 64MB(32位)或 82MB(64位),超出即抛OutOfMemoryError: PermGen space - JDK 8+:
-XX:MetaspaceSize默认约 21MB,-XX:MaxMetaspaceSize默认为-1(无上限),若不显式设置最大值,Metaspace 可持续增长直至系统内存不足,进程可能被 OS OOM Killer 杀掉
GC 触发逻辑完全不同
PermSize 本身不触发 GC;只有当已用 Perm 内存逼近 MaxPermSize 且无法扩容时,才可能引发 Full GC 清理无用类 —— 但清理成功率依赖 ClassLoader 是否可回收。
MetaspaceSize 则是明确的 GC 触发点:一旦已用元空间超过该值,JVM 就会尝试执行一次 Full GC,试图卸载无用类并重置阈值。重置后的新 MetaspaceSize 值由本次 GC 释放量决定——释放得多就调低,释放得少就调高。因此频繁 Full GC 往往说明初始值设得太小。
生产环境典型配置建议
- 避免只设
MetaspaceSize而不设MaxMetaspaceSize,防止失控增长拖垮整机 - 推荐将两者设为相同值(如
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m),消除动态调整带来的 GC 波动 - 从 JDK 7 迁移时,直接把
-XX:PermSize=128m -XX:MaxPermSize=256m替换为对应 Metaspace 参数即可,无需大幅调高 - 若应用大量动态生成类(如使用 ASM、Groovy、OSGi),需结合
jstat -gc <pid></pid>或java.lang.management.MemoryPoolMXBean监控实际元空间使用峰值,再定容











