Skip to content

GC 只对堆回收吗

GC不仅堆进行GC,并且也会对方法区进行回收

G1的回收特色是什么 ​

JVM 的回收器CMS和G1

JVM 运行时内存分为哪几块? ​

以 JDK 8 为准,JVM 运行时数据区包括五部分:程序计数器、虚拟机栈、本地方法栈、堆、元空间(方法区)。此外还有一块不属于 JVM 规范、但经常被用到的直接内存。

按是否线程共享,可以这样划分:

线程私有线程共享
程序计数器、虚拟机栈、本地方法栈堆、元空间

程序计数器 ​

记录当前线程下一条要执行的字节码指令地址,线程切换回来后靠它恢复执行位置。执行 native 方法时值为空(undefined)。它占用空间极小,是唯一不会发生 OutOfMemoryError 的区域。

虚拟机栈 ​

每个线程一个,方法每调用一次就压入一个栈帧,方法返回时弹出。栈帧中包含:

  • 局部变量表:方法参数和局部变量
  • 操作数栈:字节码运算时的临时数据
  • 动态链接:指向运行时常量池中方法的引用
  • 方法返回地址

递归太深会抛 StackOverflowError;栈可扩展但申请不到内存时抛 OutOfMemoryError。栈大小可通过 -Xss 调整。

本地方法栈 ​

与虚拟机栈作用类似,区别是它服务于 native 方法。HotSpot 中两者实际是合在一起实现的。

堆 ​

JVM 中最大的一块内存,所有线程共享,几乎所有对象实例都在这里分配,也是垃圾回收的主要区域。按分代思想划分为:

  • 新生代:Eden 区 + 两个 Survivor 区(默认比例 8:1:1),新对象一般先放在 Eden。
  • 老年代:存放经过多次 GC 仍存活的对象,以及大对象。

堆大小用 -Xms、-Xmx 设置,空间耗尽会抛 OutOfMemoryError: Java heap space。

元空间(方法区) ​

存放类的元数据,如类结构、方法信息、常量、静态变量。JDK 8 用元空间取代了永久代,并且改为使用本地内存,不再受堆大小限制,可通过 -XX:MaxMetaspaceSize 限制上限。

运行时常量池是方法区的一部分,存放编译期生成的字面量和符号引用,运行期间也能动态加入新常量,比如 String.intern()。

直接内存 ​

不属于运行时数据区,是通过 NIO 的 ByteBuffer.allocateDirect() 分配的堆外内存。它避免了在 Java 堆和本地内存之间来回复制数据,能提升 IO 性能,Netty 就大量使用。它受物理内存限制,分配过多同样会 OOM。

总结 ​

记住“三私有两共享”:程序计数器、虚拟机栈、本地方法栈随线程生灭;堆存对象、元空间存类信息,是线程共享的。面试时再补充各区域可能出现的异常和对应的调优参数,回答就比较完整了。


📮 联系方式

微信:BuZhiCoder | QQ:1776418445 扫码添加,备注「求职」优先通过

微信二维码

基于 VitePress 搭建

🌟训练营🤖AI面试📄做简历💻刷题