
Java永久代Permanent Generation简称 PermGen是 Java 虚拟机JVM在JDK 7 及以前版本中用于实现方法区的一个内存区域。理解永久代最核心的一句话是永久代是 HotSpot JVM 对“方法区”这一 JVM 规范的具体实现。就像堆是 Java 对象存放的地方一样永久代是类元数据存放的地方。以下是关于永久代的详细解析1. 永久代里存了什么在 JDK 7 之前永久代主要存储以下信息类元数据类的结构、字段、方法、构造函数等字节码信息。运行时常量池包括类编译后的字面量和符号引用。字符串常量池存储程序中的字符串字面量。静态变量类级别的变量。JIT 编译后的代码即时编译器编译后的本地机器码部分情况下。类加载器信息包括系统类加载器和自定义类加载器的引用。2. 永久代为什么被移除痛点在哪里在 JDK 8 中Oracle 正式完全移除了永久代将其替换为元空间。永久代被移除的主要原因包括内存大小固定容易发生 OOM永久代的大小在启动时通过-XX:MaxPermSize指定一旦设定很难动态调整。如果在运行时加载了大量的类例如使用大量动态代理、反射、JSP重编译的Web应用很容易抛出著名的错误java.lang.OutOfMemoryError: PermGen space。垃圾回收效率低永久代的垃圾回收Full GC条件苛刻主要针对常量池中的无用常量和卸载无用的类。由于类卸载的条件非常严格该类所有的实例都已被回收加载该类的ClassLoader已经被回收等导致永久代的内存经常只增不减引发内存泄漏。合并 HotSpot 与 JRockit 虚拟机Oracle 收购了 BEA 公司拥有 JRockit JVM打算将 HotSpot 和 JRockit 的优秀特性合并。JRockit 中并没有永久代的概念为了统一架构Oracle 决定废弃永久代。3. JDK 7 到 JDK 8 的演变重要分水岭为了平滑过渡永久代的移除是分步骤进行的JDK 6 及以前永久代完整存在包含上述所有内容。JDK 7开始“拆除”永久代。字符串常量池被从永久代移到了Java 堆中。符号引用被移到了 Native Memory本地内存。原因字符串常量池在堆中更容易被垃圾回收且与 Java 对象的生命周期管理更一致。JDK 8彻底废除永久代。将类元数据、运行时常量池等剩余内容全部移到了元空间中。4. 永久代 vs 元空间这是面试中最常被问到的对比特性永久代 (JDK 7及以前)元空间 (JDK 8及以后)所在位置JVM 进程内存中本地内存默认大小较小受限于-XX:MaxPermSize默认无上限仅受限于物理内存内存溢出风险极高 (PermGen space)较低但可能耗尽物理内存导致被OS杀死GC 触发频繁触发 Full GC元空间垃圾回收与堆解耦条件更宽松调优参数-XX:PermSize/-XX:MaxPermSize-XX:MetaspaceSize/-XX:MaxMetaspaceSize5. 面试常考考点总结方法区与永久代的关系方法区是 JVM 规范中定义的一个逻辑区域。永久代是 JDK 7 以前 HotSpot JVM 对方法区的实现。元空间是 JDK 8 及以后 HotSpot JVM 对方法区的实现。字符串常量池在哪里JDK 6永久代。JDK 7 及以后Java 堆中。为什么用元空间替换永久代因为永久代大小固定容易 OOM而元空间使用本地内存大小随需增长极大地降低了由于加载过多类导致的OOM问题。注如果你在运行 JDK 8 或更高版本的代码时在启动参数中加上了-XX:MaxPermSize512mJVM 会直接报错并拒绝启动提示该参数已被忽略或废弃。