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 扫码添加,备注「求职」优先通过
