Skip to content

面试速答(先看这里)

**一句话结论:**方法区是Java虚拟机规范定义的一块用于存储类信息、常量、静态变量、编译器编译后的代码等数据的内存区域。

60秒标准回答:

方法区是Java虚拟机规范定义的一块用于存储类信息、常量、静态变量、编译器编译后的代码等数据的内存区域

方法区是线程共享的,每个虚拟机实例只有一个方法区。 实现方法区的方式在不同的JDK厂商以及不同版本中可能有所不同的。 所谓 规范是规范,实现是实现,两码事儿

我们拿主流的HotSpot虚拟机来说明一下他的实现机制

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **要点1:**方法区是线程共享的,每个虚拟机实例只有一个方法区。
  • **要点2:**在JDK 1.7及之前的版本中,方法区通常被实现为 永久代(Permanent Generation) ,用于存储类信息、常量池、静态变量、即时编译器编译后的代码等数据。
  • **要点3:**不过在1.6中,方法区中包含了字符串常量池,而在1.7中,把字符串常量池、和静态变量都移到了堆内存中。
  • **要点4:**由于永久代有固定的大小,且不容易调整,因此在一些场景下容易导致内存溢出。
  • **要点5:**所以,从JDK 1.8开始,HotSpot虚拟机对方法区的实现进行了重大改变。

**记忆锚点:**JDK → HotSpot → Java → 元空间(Metaspace) → Generation → 义的一块用于存储类

关键取舍:

  • 元空间的内存使用量受限于操作系统对本地内存的限制。

易错提醒:

  • 但是Java中往往会有很多字符串也是朝生夕死的,将字符串常量池放到堆中,能够更高效及时地回收字符串内存 下图是1.6VS1.7的对比: 由于永久代有固定的大小,且不容易调整,因此在一些场景下容易导致内存溢出。
  • 它能够有效地避免了永久代的内存溢出问题,并且可以减少垃圾回收的压力。

加分表达:

  • 例如,如果应用程序中使用大量的动态生成类或者频繁地加载卸载类,就可能导致永久代溢出。

追问准备:

  • 围绕「JDK」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「HotSpot」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「Java」:底层原理是什么?使用时有哪些边界和常见坑?
  • 如果线上出现异常,你会如何定位、验证并规避?

典型回答 ​

方法区是Java虚拟机规范定义的一块用于存储类信息、常量、静态变量、编译器编译后的代码等数据的内存区域。

方法区是线程共享的,每个虚拟机实例只有一个方法区。**实现方法区的方式在不同的JDK厂商以及不同版本中可能有所不同的。**所谓规范是规范,实现是实现,两码事儿。

我们拿主流的HotSpot虚拟机来说明一下他的实现机制。

在JDK 1.7及之前的版本中,方法区通常被实现为永久代(Permanent Generation),用于存储类信息、常量池、静态变量、即时编译器编译后的代码等数据。

不过在1.6中,方法区中包含了字符串常量池,而在1.7中,把字符串常量池、和静态变量都移到了堆内存中。这么做的主要原因是因为永久代的 GC 回收效率太低,只有在FullGC的时候才会被执行回收。但是Java中往往会有很多字符串也是朝生夕死的,将字符串常量池放到堆中,能够更高效及时地回收字符串内存

下图是1.6VS1.7的对比:

image.png

image.png

由于永久代有固定的大小,且不容易调整,因此在一些场景下容易导致内存溢出。例如,如果应用程序中使用大量的动态生成类或者频繁地加载卸载类,就可能导致永久代溢出。

所以,从JDK 1.8开始,HotSpot虚拟机对方法区的实现进行了重大改变。永久代被移除,取而代之的是元空间(Metaspace)。元空间是使用本地内存(Native Memory)来存储类的元数据信息的,它不再位于堆内存中。

image.png

元空间的特点是可以根据应用程序的需要动态调整其大小,因此更加灵活。它能够有效地避免了永久代的内存溢出问题,并且可以减少垃圾回收的压力。元空间的内存使用量受限于操作系统对本地内存的限制。