Java 面试实战:从局部变量看 JVM 垃圾回收机制
在 Java 面试中,一个简单的局部变量声明往往能引出对 JVM 底层机制的深度追问。以下是对垃圾回收(GC)核心问题的梳理与解析。
局部变量的生命周期与 GC Roots
当创建一个局部 byte 类型数组时:
byte[] arrays = new byte[1024];
该数组对象何时被回收?关键在于引用关系。当方法执行结束,栈帧中的局部变量表空间被重用,且无其他引用指向该对象时,它便成为可回收对象。
JVM 通过'可达性分析算法'判断对象存活。以 GC Roots 为起点遍历引用链,不可达的对象即被视为死亡。常见的 GC Roots 包括:
- 虚拟机栈中引用类型的局部变量;
- 方法区中类静态属性引用的对象;
- 常量池中引用的对象;
- 本地方法栈中 JNI 的引用等。
对象存活判定与 Finalize 方法
被标记为可回收的对象不一定立即回收。若对象重写了 finalize() 方法且未被执行过,虚拟机会将其放入 F-Queue 队列,由低优先级线程执行该方法。若在 finalize() 中重新建立了与 GC Roots 的引用,对象将复活并继续存活。
GC 类型区分:Minor、Major 与 Full
- Minor GC:发生在新生代(Eden + Survivor),频率高,速度快,通常伴随 Stop-The-World。
- Major GC:清理老年代,通常伴随至少一次 Minor GC。
- Full GC:全局范围,涉及新生代、老年代及元空间(Metaspace)。Full GC 不等于 Major GC,具体行为取决于使用的垃圾收集器组合。
常见垃圾回收算法
- 标记 - 清除:简单但会产生内存碎片,影响大对象分配效率。
- 复制算法:将内存分为两块,轮流使用。常用于新生代,解决了碎片问题,但牺牲了一半空间。
- 标记 - 整理:标记后向一端移动存活对象,回收边界外空间。解决了碎片问题且空间利用率高,常用于老年代。
- 分代收集:根据对象生命周期划分区域,新生代用复制算法,老年代用标记 - 清除或整理算法。
方法区的垃圾回收
方法区存储类信息、静态变量等。虽然规范允许不实现 GC,但 HotSpot 支持对废弃常量和无用类的回收。类被回收需满足三个条件:堆中无实例、类加载器已回收、Class 对象无引用且无法通过反射访问。可通过 -Xnoclassgc 参数控制。
内存配置原则
新生代配置
- 追求响应时间:适当调大,减少 GC 频率。
- 追求吞吐量:尽量设置大,让短期对象在新生代回收。
- 避免过小:防止 YGC 频繁导致对象过早进入老年代引发 Full GC。
老年代配置
- 追求响应时间:配合 CMS 等收集器,需平衡大小以避免碎片或停顿过长。
- 追求吞吐量:大新生代、小老年代,加速短期对象回收。


