初探JVM垃圾回收机制

本文探讨了JVM如何识别垃圾对象,通过引用计数法和可达性分析两种方法,并详细介绍了各种垃圾回收算法,如标记清除、复制、标记整理、分代收集和分区收集。此外,还列举了多种垃圾收集器,如Serial、ParNew、Parallel Scavenge等,以及CMS和G1的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1JVM心中的垃圾对象长什么样子?(确定垃圾)

主要通过下面两个方法来确定这个对象是否为垃圾对象

1:引用计数法

java里面在操作对象之前,需要先拿到对象的引用,引用记数法就是通过计算这个引用确定,在为对象添加一个引用时,引用计数加1,删除时,引用计数减1,当引用计数为0时则表示这个对象没有被引用,就可以确定它是一个垃圾了

缺点:如果有循环引用,则引用计数一直不为0,一直无法被回收

2:可达性分析

解决了引用记数法的循环引用问题

可达性分析通过定义一个GC Root对象,向下搜索,搜索的路径被称为引用链,如果一个对象和GCRoot之间没有一个引用链,则该对象就是不可达的,会被标记出来,标记出来会进行一次筛选(根据finalize方法)。若经过筛选,判定可回收,那么就会立即回收;若判定没有必要回收,那么就将对象放入F-Queue队列中,进行二次筛查。二次筛查会执行对象的finalize()方法。若对象在这个过程重新与引用链上的任何一个对象建立关联,那么该对象就会从回收集合中移除。否则,对象会被回收。

缺点:

1.消耗大量时间,因为GCRoot是全局引用
2:GC停顿,为了保持整个系统的一致性

2在确定需要回收的垃圾后,应该怎么回收垃圾呢?(垃圾回收算法)

1.标记清除算法

标记清除算法分为标记阶段和清除阶段,通过从根集合(GC Roots)进行扫描,对存活的对象
进行标记,标记完毕后,再扫描整个空间中未被标记的对象,进行清除回收

场景:存活对象较多
优点:不需要进行对象的移动,只需对不存活的对象进行处理,在存活对象比较多的情况下极为高效
缺点:容易引起内存碎片化的问题,继而引起大对象无法获得连续可用空间的问题

2.复制算法

复制算法首先将内存分为两个区域,新创建的对象都存放在区域1,当区域1满了过后会对区域1还存活着的对象进行一次标记,然后把这些标记的对象全部复制到区域2,复制完成就把直接把区域1整个区域清除回收
优点:解决了内存碎片化问题
场景:存活对象较少
缺点:
1:内存浪费,因为被分成了两份,在同一时刻最多只有一半的内存被使用
2:效率低,因为当有很多存活的对象时,会经常来回的复制

3.标记整理算法

标记整理算法利用了标记清除算法和复制算法的优点,他先将存活的对象标记出来,然后将这些对象都向端的一侧移动,移动之后的对象就存储一块连续的内存了,然后直接回收端的另一侧就好了

优点:解决了内存碎片化问题,内存浪费问题
缺点:效率低(移动对象,整理对象的引用地址造成的)

4.分代收集算法

分代收集算法是根据对象所在的内存区域来选择不同的算法来进行回收,垃圾回收的主要区域为堆内存区域,堆内存主要分为新生代,老年代和永久代,针对不同的区域使用不同的回收算法,
新生代:复制算法(存活的对象较少,对象的生命周期短)
老年代:标记整理算法(存活的对象较多,生命周期长且占用内存大)

因为新生代采用复制算法,所以新生代里面又分为Eden区域和servivor区域

5.分区收集算法

分区算法将整个堆空间划分为连续的大小不同的小区域,对每个小区域都单独进行内存使用和垃圾回收
优点:缩短了垃圾回收的系统停顿时间

3. 回收垃圾的方法有了,谁来做这件事呢?(垃圾收集器)

1.Serial(串行收集器)

特点:

 1. 实现复制算法进行垃圾回收
 2. 单线程,回收垃圾时会暂停所有工作线程
 3. 简单,高效,在client模式下是新生代的默认垃圾收集器

场景:适用于内存不大的应用

2.ParNew

特点

 1. 实现复制算法进行垃圾回收
 2. 多线程,垃圾回收过程会暂停所有工作线程
 3. 默认开启cpu同等数量的线程进行垃圾回收,可以通过设置XX:ParallelGCThreads参数调节线程数
 4. 在server模式下新生代默认的垃圾收集器

3.Parallel Scavenge

特点:

 1. 实现复制算法进行垃圾回收
 2. 多线程,更高效的利用了CPU,提高了系统吞吐量
 3. 提供三个参数(最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数, 控制吞吐量大小的-XX:GCTimeRatio参数和控制自适应调节策略开启与否的UseAdaptiveSizePolicy参数) 的自适应调节策略,提高系统吞吐量,

4.Serial Old

特点:


 1. 实现标记整理算法
 2. 单线程的
 3. jvm在client模式下老年代默认的垃圾收集器

5.Parallel Old

特点:

 1. 实现标记整理算法
 2. 多线程
 3. jvm在server模式下老年代的垃圾收集器

6.CMS

垃圾收集过程


 1. 初始标记:标记GCRoot直接关联的对象,需要暂停所有线程,速度很快
 2. 并发标记:和工作线程一起,执行GCRoot跟踪标记过程,不需要暂停所有线程
 3. 重新标记:修正在并发标记过程中部分对象的状态变化,需要暂停所有线程
 4. 并发清除:清除不可达对象,不需要暂停所有线程

特点

  1. 实现标记清除算法,用于老年代的垃圾收集器
  2. 多线程
  3. 垃圾收集停顿时间短,系统稳定性高

7.G1

回收过程:


1). 标记阶段,首先初始标记(Initial-Mark),这个阶段是停顿的(Stop the World Event),并且会触发一次普通Mintor GC。对应GC log:GC pause (young) (inital-mark)
2)、Root Region Scanning,程序运行过程中会回收survivor区(存活到老年代),这一过程必须在young GC之前完成。
3)、Concurrent Marking,在整个堆中进行并发标记(和应用程序并发执行),此过程可能被young GC中断。在并发标记阶段,若发现区域对象中的所有对象都是垃圾,那个这个区域会被立即回收(图中打X)。同时,并发标记过程中,会计算每个区域的对象活性(区域中存活对象的比例)。
4)、Remark, 再标记,会有短暂停顿(STW)。再标记阶段是用来收集 并发标记阶段 产生新的垃圾(并发阶段和应用程序一同运行);G1中采用了比CMS更快的初始快照算法:snapshot-at-the-beginning (SATB)。
5)、Copy/Clean up,多线程清除失活对象,会有STW。G1将回收区域的存活对象拷贝到新区域,清除Remember Sets,并发清空回收区域并把它返回到空闲区域链表中。
6)、复制/清除过程后。回收区域的活性对象已经被集中回收到深蓝色和深绿色区域。唯一和串行垃圾回收器不同的是,并行垃圾回收器是使用多线程来进行垃圾回收工作的。

特点:

 1. 精确控制停顿时间,提高了系统吞吐量
 2. 多线程
 3. 实现了标记整理算法,不产生内存碎片

回收垃圾的人有了,那该什么时候去回收垃圾呢?


 1. 在新生代的Eden区满了会触发新生代GC(MiMor GC)
 2. 新生代升级成老年代时,老年代内存不足时会触发老年代gc(Full GC)
 3. 当程序调用System.gc()时会触发Full GC。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值