JDK 1.8 JVM内存模型核心变化是永久代被元空间取代:元空间使用本地内存而非堆内存,不参与堆GC,由-XX:MetaspaceSize和-XX:MaxMetaspaceSize控制,字符串常量池仍在堆中,运行时常量池移至元空间。
JDK 1.8 的 JVM 内存模型最核心变化是:永久代(PermGen)被彻底移除,由元空间(Metaspace)替代——这不只是换个名字,而是内存归属、GC 行为和调优逻辑的根本性重构。
java.lang.OutOfMemoryError: PermGen space
因为元空间不再使用 JVM

-XX:PermSize 和 -XX:MaxPermSize 参数在 JDK 1.8 中已完全失效,继续配置会被 JVM 忽略(启动时可能报 warning)-XX:MetaspaceSize(触发首次元空间 GC 的初始阈值)和 -XX:MaxMetaspaceSize(硬上限,默认不限)"abc" 这类字面量)早在 JDK 1.7 就已从永久代移到堆中,JDK 1.8 仍保留在堆里;但运行时常量池(如类的符号引用、字段/方法签名等)现在属于元空间管理新生代(Eden + S0/S1)、老年代、GC 策略这些堆内划分与 JDK 1.7 一致,但“方法区”这个逻辑概念,现在由元空间承载,且它不参与任何堆 GC 周期。
MetaspaceSize 水位)fastjson),减少重复加载开销;而永久代每个 ClassLoader 都要单独占一份-XX:MaxMetaspaceSize,元空间持续增长最终会耗尽本地内存,导致进程被 OS OOM-killer 杀掉(错误日志里看不到 Java OOM,只有 Killed process)虚拟机栈、本地方法栈、程序计数器这些线程私有区域,在 JDK 1.8 中行为完全不变,StackOverflowError 和 OutOfMemoryError 的触发条件也一样。
OutOfMemoryError 的区域,且永远只存当前字节码行号或 null(native 方法时)java.lang.OutOfMemoryError: Java heap space,该调 -Xms/-Xmx 还得调真正容易被忽略的是:元空间的 GC 不是“自动友好型”,它只在达到 MetaspaceSize 后才尝试回收无用类,且是否成功取决于类加载器是否被回收。如果应用频繁生成类(如大量使用 CGLIB、Groovy 脚本、热部署),又没正确释放 ClassLoader,元空间会持续上涨直到触达 MaxMetaspaceSize 或本地内存极限——这时候看监控,会发现 GC 日志里 Metadata GC Threshold 反复出现,但元空间使用量却下不去。