明天你会感谢今天奋力拼搏的你。
ヾ(o◕∀◕)ノヾ
在 Java 中,垃圾回收(Garbage Collection,简称 GC)是一项非常重要的机制,它帮助开发者自动管理内存,避免手动内存管理带来的复杂性和潜在错误。本文主要介绍 垃圾回收的基础原理、分代收集机制和不同JDK版本中的回收机制。
Java 采用自动内存管理机制,这意味着开发者不需要手动分配和释放内存。当创建一个对象时,Java 虚拟机(JVM)会自动为该对象分配内存;而当对象不再被使用时,垃圾回收器会自动回收这些对象所占用的内存。
如何判断一个对象是“垃圾”?Java通过可达性分析实现。
Java 垃圾回收器使用可达性分析算法来确定哪些对象是 “垃圾”,即哪些对象不再被使用,可以被回收。该算法的基本思想是从一组被称为根对象(GC Roots)的对象开始,通过引用关系遍历对象图,能够被GC Roots直接或间接引用到的对象被认为是 “可达” 的,而那些无法被 GC Roots 引用到的对象则被认为是 “不可达” 的,这些不可达对象就是垃圾对象,可以被回收。
常见的GC Roots包括:
对上面虚拟机栈、方法区不理解的可以查看我的另一篇文章介绍Java的虚拟机结构
通过可达性Java可以判断哪些对象是“垃圾”了,但GC不止于此,就比如一个人的房间,如果东西胡乱摆放,清理会越来越困难,如果能分类常用的放哪里、不常用的放哪里,清理起来就会更方便。
分代收集理论是 Java 垃圾回收的重要基础,它基于两个分代假说:
根据这两个假说,Java 堆被划分为不同的区域,主要包括新生代和老年代。新生代用于存放新创建的对象,这些对象通常很快就会变成垃圾;老年代用于存放存活时间较长的对象。不同代的对象采用不同的垃圾回收算法,以提高垃圾回收的效率。
内存分代模型:
| 区域 | 说明 |
|---|---|
| 新生代 | 存放新创建的对象,分为 Eden 区和两个 Survivor 区(S0, S1) |
| 老年代 | 存放长期存活的对象(经过多次GC仍存活的对象) |
| 元空间 | 存放类元数据(Java 8+,替代了永久代,使用本地内存) |
对标记为可回收的对象进行回收,释放其所占用的内存空间。常见的清除算法有:
分代收集算法会根据对象存活周期的不同将内存划分为几块,一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
当创建一个新对象时,JVM 会根据对象的大小和类型,将其分配到不同的内存区域。通常,新创建的对象会被分配到新生代的 Eden 区。当Eden区满时就会触发新生代的垃圾回收(Minor GC)。
随着新对象的不断创建,Eden 区会逐渐被填满。当Eden区满时,会触发一次Minor GC。Minor GC的主要流程如下:
如果 Eden 区和 Survivor 区都无法容纳某个大对象,这个对象会被直接分配到老年代。
老年代主要用于存放存活时间较长的对象,其垃圾回收频率相对较低,回收过程也相对复杂。
Major GC 是指发生在老年代的垃圾回收过程,主要用于回收老年代中的垃圾对象,释放内存空间。当老年代空间不足时触发Major GC。
不同的回收器策略不同,老年代常用的垃圾回收算法包括:
特点
Full GC 是指对整个堆(包括年轻代、老年代)以及方法区(Metaspace/PermGen)的垃圾回收。某些情况下还会触发其他区域的回收(如堆外内存或类卸载)。
触发条件:
回收行为:
Full GC 会暂停所有应用线程(Stop-The-World, STW),对堆内存进行全面回收。
具体算法取决于垃圾收集器:
特点:
随着JDK版本的发展,GC的机制也一直在演进优化,如下介绍了各个JDK版本可能使用到的GC机制:
| GC 机制 | 哪些 JDK 使用 | 描述 | 适用场景 |
| 串行垃圾回收器(Serial GC) | JDK 1.2 - JDK 17 | 单线程进行垃圾回收,进行时会暂停所有用户线程。新生代用复制算法,老年代用标记 - 整理算法 | 单 CPU 环境下的小型应用程序 |
| 并行垃圾回收器(Parallel GC) | JDK 1.2 - JDK 17 | 新生代和老年代都使用多线程进行垃圾回收,新生代采用复制算法,老年代采用标记 - 整理算法。JDK 7 及以后支持自适应调节策略,JDK 9 起成为默认 GC | 对吞吐量要求较高、对停顿时间要求不是特别苛刻的应用程序,如批量数据处理任务 |
| 并发标记清除垃圾回收器(CMS GC) | JDK 1.4 - JDK 1.8 | 以获取最短回收停顿时间为目标,采用标记 - 清除算法。过程分为初始标记、并发标记、重新标记、并发清除,初始和重新标记需 STW。(JDK 9 标记为废弃,JDK 14 移除。) | 对响应时间要求较高的应用程序,如 Web 应用 |
| G1 垃圾回收器(Garbage First) | JDK 7u4 - JDK 17 | 将堆内存划分为多个大小相等的 Region,新生代和老年代不再物理隔离。采用标记 - 整理和复制算法,优先回收垃圾最多的 Region | 大内存、多 CPU 的服务器应用,可同时满足高吞吐量和低停顿要求 |
| ZGC(Z Garbage Collector) | JDK 11 - JDK 17 | 可扩展的低延迟垃圾回收器,采用染色指针和读屏障技术,能在短时间完成回收,停顿时间几乎可忽略,支持 TB 级堆内存 | 对响应时间要求极高、内存使用量大的应用,如大型数据库、实时数据分析系统 |
| Shenandoah GC | JDK 12 - JDK 17 | 追求低延迟的垃圾回收器,通过与用户线程并发执行来减少停顿时间 | 对低延迟有严格要求的应用 |
JDK 7 及以前:
JDK 8:
JDK 9 及以后:
Java官网垃圾回收基础教程:https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
Java SE 17垃圾回收调优介绍:https://docs.oracle.com/en/java/javase/17/gctuning/introduction-garbage-collection-tuning.html
全部评论