12. 垃圾回收机制
12.1. 垃圾回收机制简介
GC是Java的“自动清洁工”,专门回收程序不再使用的内存,防止内存泄漏, 就像不用了的空饮料瓶,系统自动帮你扔掉。
- 垃圾回收机制有效的防止了内存泄露,可以有效的使用可使用的内存。 垃圾回收器通常作为一个单独的低级别的线程运行,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会对内存堆中已经死亡的或很长时间没有用过的对象进行清除和回收。
- 对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。
- 通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达 ",哪些对象是"不可达"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。 程序员可以手动执行
System.gc()通知GC运行。
12.2. 怎么判断对象是否可以被回收?
- 垃圾收集器在做垃圾回收的时候,首先需要判定的就是哪些内存是需要被回收的,哪些对象是「存活」的,是不可以被回收的;哪些对象已经「死掉」了,需要被回收。
- 一般有两种方法来判断:
- 引用计数器法:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1, 当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题;
- 可达性分析算法:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。 (一般都用这个)
12.3. 垃圾回收的算法
- 标记-清除法:分为标记和清除两个阶段。首先标记出所有存活的对象,然后清除所有未被标记的对象。
- 标记-复制法:将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这块内存用完时,就将还存活的对象复制到另一块内存上,然后清空当前内存块。
- 标记-整理法:结合了1,2的优点。标记阶段与标记-清除算法相同,但在清除阶段,不是直接清除未标记的对象,而是让所有存活的对象都向一端移动,然后清理掉端边线以外的内存。
- 三色标记法:将对象分为白色、灰色和黑色三种状态。通过初始标记、并发标记和重新标记三个阶段来标记对象,以减少STW(Stop The World)的时间。
- 分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代和永久代,新生代基本采用复制算法,老年代采用标记整理算法。
STW 是垃圾回收时 暂停所有应用线程 的行为, 确保垃圾回收器能安全地标记/清理对象,避免回收过程中应用线程修改对象引用(否则会漏标或误删)。
- 白色表示对象尚未被扫描,即未被标记为存活对象。
- 灰色表示对象已经被扫描,但其引用的其他对象尚未被扫描。
- 黑色表示对象已经被扫描,并且其引用的其他对象也已经被扫描
12.4. 垃圾回收的触发条件
- 内存分配达到阈值:堆内存空闲不足以满足新对象的分配需求的时候可能会被触发
- 特定区域内存满了:
- 年轻代:JVM中,新创建的对象通常首先被分配到年轻代的Eden区。当Eden区满了时会触发
- 老年代:老年代没有足够的空间容纳新的对象或年轻代中晋升的对象时会触发
- 元空间:元空间用于存储类的元数据。当元空间满了时也会触发
- 显式调用垃圾回收:调用
System.gc()方法显式地建议JVM进行垃圾回收 - 系统内存压力:系统内存不足的时候
- 特定垃圾回收器策略:G1垃圾回收器的CMS垃圾回收器
G1:年轻代和老年代内存达到阈值出发混合回收
CMS:老年代垃圾使用到一定的比例时触发
垃圾回收参考材料:
Java的内存管理机制之(垃圾回收(GC)原理)_java内存回收机制原理-CSDN博客
13. CMS垃圾回收器
- CMS垃圾回收器 是 JVM 中一种以 低延迟 为目标的垃圾回收器,主要用于老年代的垃圾回收。它通过 并发标记-清除算法 减少垃圾回收时的停顿时间(STW),适合对响应速度敏感的应用(如 Web 服务、实时系统)。
- 通过“初始标记-并发标记-重新标记-并发清除”四阶段实现,减少停顿时间
- JDK9被标记废弃,JDK14正式移除
- CMS 的核心设计目标 :
- 最小化 STW(Stop-The-World)时间:通过并发执行大部分回收阶段,减少用户线程的停顿。
- 适用场景:适合内存较大、对延迟敏感的老年代回收(JDK 9 后已不推荐使用,逐渐被 G1、ZGC 等替代)。

CMS垃圾回收参考材料:
14. 分代垃圾回收器
前景引入:在大多数程序中,新创建的对象往往很快就会变得不可达(即不再使用),而长时间存活的对象则有可能继续存活下去
回收原理:在不同代使用不同的垃圾回收算法用来提高效率
基本概念:分代垃圾回收的核心思想是将堆内存划分为多个区域或代
- 年轻代 : 这个代存放的是新创建的对象。年轻代的垃圾回收频率较高,大部分生命周期较短,很快就会变得不可达,因此新生代会频繁地进行垃圾回收
- 细分为 Eden 区和两个 Survivor 区(通常称为 S0 和 S1)
- 老年代 : 经过多次垃圾回收仍然存活下来的对象会被移动到老年代。老年代中的对象存活时间较长,垃圾回收的频率较低。
- 永久代(元空间): 该代存放的是程序运行时需要的类信息、方法、常量等数据,而不是普通的对象数据。在Java 8之前,永久代作为HotSpot JVM的一部分,之后被元空间取代。元空间不在Java堆内存中,而是使用本地内存。
简单介绍三代的详细工作流程:
- 新生代:主要采用复制算法
- 每次垃圾回收时,将Eden区和一个Survivor区的存活对象复制到另一个Survivor区,然后清空Eden区和被复制的Survivor区。
- 每次 Minor GC 后,对象的年龄增加 1。当对象的年龄达到一定阈值(默认是 15)时,对象会被晋升到老年代
- 老年代:标记-清除、整理算法
- 标记-清除法:首先标记出所有可达对象,然后清除未被标记的对象。
- 标记-整理法:在标记-清除的基础上,对存活对象进行整理,消除内存碎片。
- 永久代、元空间 : Full GC
- 永久代(Java 8 以前):存储类的元数据信息,通常在 Full GC 时进行垃圾回收。
- 元空间(Java 8 及以后):存储类的元数据信息,使用本地内存,通常在 Full GC 时进行垃圾回收。
分代垃圾回收参考材料:

9627

被折叠的 条评论
为什么被折叠?



