Java技术八股学习Day17

JVM垃圾回收详解

堆空间结构与内存分配回收原则

JVM 堆(GC 堆)是垃圾回收核心区域,基于分代收集思想划分:JDK1.7 及之前分为新生代(Eden 区、两个 Survivor 区 S0/S1)、老年代、永久代;JDK1.8 后永久代被元空间(本地内存实现)取代,新生代和老年代结构保持不变。内存分配遵循三大原则:对象优先在 Eden 区分配,Eden 区满则触发 Minor GC;大对象(需大量连续内存,如字符串、数组)直接进入老年代,避免新生代频繁 GC;长期存活对象(Survivor 区中每经历一次 Minor GC 年龄 + 1,默认年龄达 15 或动态年龄计算达标)晋升老年代,动态年龄计算指当某一年龄对象总大小超过 Survivor 区 50%,取该年龄与 MaxTenuringThreshold 最小值作为晋升阈值。

垃圾回收(GC)分类

GC 按回收范围分为 Partial GC(部分收集)和 Full GC(整堆收集):Partial GC 包括仅回收新生代的 Minor GC(Young GC)、仅回收老年代的 Old GC(仅 CMS 支持)、回收新生代 + 部分老年代的 Mixed GC(仅 G1 支持);Full GC 回收整个堆(新生代、老年代)和方法区,触发场景包括老年代空间不足、永久代 / 元空间不足、Minor GC 前晋升对象平均大小超老年代剩余空间等。空间分配担保机制确保 Minor GC 安全:JDK6 Update24 后,只要老年代连续空间大于新生代对象总大小或历次晋升平均大小,即执行 Minor GC,否则触发 Full GC。

死亡对象判断方法

判断对象是否可回收有两种核心算法:一是引用计数法,通过对象引用计数器增减判断,简单高效但无法解决循环引用问题,主流虚拟机未采用;二是可达性分析算法,以 GC Roots 为起点,沿引用链搜索,不可达对象判定为可回收,GC Roots 包括虚拟机栈局部变量表引用对象、本地方法栈 Native 方法引用对象、方法区静态属性 / 常量引用对象、同步锁持有的对象等。不可达对象并非必然回收,需经历两次标记:首次标记后筛选是否需执行 finalize () 方法,无需执行则直接回收,需执行则放入队列二次标记,若二次标记前未建立新引用则回收,finalize () 方法已逐渐被弃用。

引用类型(JDK1.2 后扩充)

Java 引用强度从强到弱分为四类:强引用(程序中普通赋值,如 String str = new String ("abc")),内存不足时虚拟机宁愿抛 OOM 也不回收;软引用(SoftReference),内存充足时不回收,不足时回收,适用于内存敏感的高速缓存;弱引用(WeakReference),GC 扫描时无论内存是否充足都会回收,生命周期短于软引用;虚引用(PhantomReference),不影响对象生命周期,仅用于跟踪对象回收过程,必须与引用队列关联使用。

废弃常量与无用类判断

  • 废弃常量:运行时常量池中,若常量(如字符串 "abc")无任何对象引用,则为废弃常量,可被回收;JDK1.7 后字符串常量池移至堆,JDK1.8 后方法区实现改为元空间,运行时常量池仍在方法区。
  • 无用类:需同时满足三个条件:堆中无该类任何实例、加载该类的 ClassLoader 已回收、该类的 Class 对象无任何引用(无法通过反射访问),虚拟机可选择回收无用类,而非必然回收。

垃圾收集算法

  • 标记 - 清除算法:分标记(标记可达对象)和清除(回收未标记对象)两阶段,效率低且产生大量内存碎片,是基础算法。
  • 复制算法:将内存分为大小相等的两块,仅使用一块,满后复制存活对象到另一块并清理原块,解决碎片问题,但可用内存减半,适合新生代(存活对象少)。
  • 标记 - 整理算法:标记后将存活对象向一端移动,清理端边界外内存,无碎片但效率较低,适合老年代(存活对象多)。
  • 分代收集算法:结合上述算法,新生代用复制算法,老年代用标记 - 清除或标记 - 整理算法,是当前虚拟机主流算法。

垃圾收集器(HotSpot 虚拟机)

垃圾收集器是收集算法的具体实现,需根据场景选择:

  • Serial 收集器:单线程收集,新生代用复制算法,老年代用标记 - 整理算法,GC 时暂停所有用户线程(STW),简单高效,适用于 Client 模式。
  • ParNew 收集器:Serial 的多线程版本,行为与 Serial 一致,可与 CMS 配合,适用于 Server 模式。
  • Parallel Scavenge 收集器:多线程复制算法,关注吞吐量(用户代码运行时间 / CPU 总时间),支持自适应调节策略,JDK1.8 默认新生代收集器,搭配 Parallel Old(老年代多线程标记 - 整理算法)。
  • Serial Old 收集器:Serial 的老年代版本,单线程标记 - 整理算法,作为 CMS 后备方案。
  • CMS 收集器:以低停顿为目标,多线程标记 - 清除算法,分初始标记(STW)、并发标记、重新标记(STW)、并发清除四阶段,并发收集但对 CPU 敏感、产生碎片、无法处理浮动垃圾,JDK14 已移除。
  • G1 收集器:面向服务器,JDK9 后默认,划分堆为多个 Region,结合标记 - 复制(局部)和标记 - 整理(整体)算法,支持并行并发、分代收集、空间整合、可预测停顿,优先回收价值高的 Region。
  • ZGC 收集器:JDK11 引入,JDK15 正式可用,标记 - 复制算法优化版,暂停时间控制在毫秒级,不受堆大小影响(最大支持 16TB),JDK21 支持分代 ZGC,停顿时间可缩短至 1 毫秒内。
相关推荐
铁蛋AI编程实战10 分钟前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
晚霞的不甘21 分钟前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
马猴烧酒.21 分钟前
【面试八股|JVM虚拟机】JVM虚拟机常考面试题详解
jvm·面试·职场和发展
SunnyDays101123 分钟前
使用 Java 冻结 Excel 行和列:完整指南
java·冻结excel行和列
奶茶精Gaaa33 分钟前
工具分享--json在线转换工具
学习
摇滚侠34 分钟前
在 SpringBoot 项目中,开发工具使用 IDEA,.idea 目录下的文件需要提交吗
java·spring boot·intellij-idea
云姜.39 分钟前
java多态
java·开发语言·c++
李堇42 分钟前
android滚动列表VerticalRollingTextView
android·java
wdfk_prog1 小时前
[Linux]学习笔记系列 -- [drivers][I2C]I2C
linux·笔记·学习
盐焗西兰花1 小时前
鸿蒙学习实战之路-Reader Kit自定义字体最佳实践
学习·华为·harmonyos