什么是方法区?是如何实现的?

1 个回答

  • 小王子-B613
    用顺其自然态度过随遇而安的生活.
    ### **1. 方法区简介** 方法区是 JVM 规范定义的一块用于存储**类信息、常量、静态变量、JIT 编译后的代码**等数据的内存区域。 - 方法区是**线程共享**的,所有线程都可以访问该区域的数据。 - 每个 JVM 实例**只有一个方法区**。 - 方法区属于**JVM 运行时数据区**,但不在堆中。 ### **2. 方法区存储内容** 1. **类的元信息**(类名、字段、方法、访问修饰符)。 2. **运行时常量池**(字面量、符号引用)。 3. **静态变量**(static 修饰的变量)。 4. **JIT 编译后的代码**(即时编译生成的本地代码)。 ## **3. 方法区的不同实现** JVM 规范只定义了方法区的作用,不同 JVM 实现方式可能不同。以下是 HotSpot JVM 在不同 JDK 版本的实现方式: ### **JDK 1.6 及之前:方法区 = 永久代(PermGen)** - **存储内容** - 类的元信息 - 运行时常量池(包括字符串常量池) - 静态变量 - JIT 编译后的代码 - **问题** - GC 效率低,仅在 Full GC 时清理 - 空间固定,不易扩展 - 字符串常量池在永久代,导致大量字符串时容易 OOM ### **JDK 1.7:优化调整** - **字符串常量池移至堆** - **静态变量移至堆** - **运行时常量池仍在永久代** - **避免 `String.intern()` 过多导致 OOM** ### **JDK 1.8 及之后:方法区 = 元空间(Metaspace)** - **存储内容** - 类的元信息 - 运行时常量池 - JIT 编译后的代码 - **特点** - **使用本地内存**,不在堆中 - **无固定大小限制**,默认动态扩展 - **受限于操作系统内存** - **支持类卸载,减少 Full GC 影响** ## **4. 方法区的 GC 机制** - **JDK 1.6 及之前** - 仅在 Full GC 触发类卸载,回收效率低 - **JDK 1.8 及之后** - 可动态扩展 - JVM 定期扫描未使用的类并卸载,释放 `Metaspace` - `-XX:+ClassUnloading` 允许卸载未使用的类,减少 `Metaspace` 占用 ## **5. 方法区 OOM 及优化** ### **JDK 1.6 及之前** - **`java.lang.OutOfMemoryError: PermGen space`** - **原因** - 动态加载过多类 - 频繁 `String.intern()` - **解决** ```shell -XX:PermSize=128m -XX:MaxPermSize=512m ``` ### **JDK 1.8 及之后** - **`java.lang.OutOfMemoryError: Metaspace`** - **原因** - 过多类加载导致 `Metaspace` 超限 - `-XX:+ClassUnloading` 关闭,导致类无法卸载 - **解决** ```shell -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=1g ``` ## **6. 总结** | **JDK 版本** | **方法区实现** | **存储内容** | **GC 机制** | **OOM 触发原因** | |------------|------------|------------|------------|------------| | **JDK 1.6 及之前** | **永久代(PermGen)** | 类信息、常量池、静态变量 | 仅 Full GC 触发 | `PermGen space` OOM | | **JDK 1.7** | **优化永久代** | 字符串常量池、静态变量移至堆 | 仍依赖 Full GC | 仍可能 `PermGen space` OOM | | **JDK 1.8 及之后** | **元空间(Metaspace)** | 类信息、运行时常量池、JIT 代码 | 可动态扩展,支持类卸载 | `Metaspace` OOM | ## **7. 最佳实践** - **动态生成类较多(Spring、CGLIB、JSP)**,增大 `MetaspaceSize` ```shell -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=1g ``` - **开启 `-XX:+ClassUnloading` 允许类卸载** - **避免 `String.intern()` 过多,减少 `Metaspace` 占用**
    发布于 2025-03-13 15:49 •IP属地 山东
    举报
    评论
    收藏