Software Engineer · 语言与工程基础

Java GC:可达性、停顿与仍被引用的内存泄漏

解释垃圾回收如何判定对象存活,为什么缓存与监听器仍可能泄漏。

题目重点:解释垃圾回收如何判定对象存活,为什么缓存与监听器仍可能泄漏。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 未指定回收器;以可达性为共通概念,分代与并发策略是实现选择。

解题路线

  1. 从 GC roots 沿引用图找存活对象;失去可达路径的对象才具备回收资格,引用计数不能单独处理环。循环引用在不可达时并不必然泄漏。
  2. 标记、清除、整理或复制是不同策略,可结合使用。分代基于对象寿命分布的经验,并非每个实现或配置都同样工作。
  3. 停顿与吞吐、堆占用、分配率有关。先看 GC 日志、存活曲线、分配热点与延迟相关性,再选择容量或回收器参数。
  4. 业务泄漏通常是仍可达但不再需要的数据,例如静态 map、未移除监听器或无上限队列。弱引用也不能代替完整生命周期管理。

手动走一遍

请求完结后对象仍在全局 map 里,GC 正确地认为它存活;增大堆仅延迟问题。一个彼此引用的对象环没有 roots 路径后可以回收;不应照搬纯引用计数结论。

规模与取舍

图遍历成本与存活对象/引用规模相关,但具体停顿不能仅由 O(n) 推断。用 P99、分配率、存活集与安全余量衡量。

易错点与追问

容易失分的边界

  • 调用 System.gc 保证立即回收。
  • GC 自动关闭所有资源。
  • 只看平均吞吐忽略尾延迟。

继续深挖

  • 为什么文件句柄仍需显式关闭?
  • 如何验证一次缓存容量修复真的降低存活集?
✓已复制微信号!