垃圾回收算法与垃圾回收器

垃圾收集算法

1.Mark-Sweep(标记-清除)算法
这是最基础的垃圾回收算法。标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。

它的主要缺点有两个:一个是效率问题,标记和清除过程的效率都不高;另外一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

2.Copying(复制)算法
为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。

目前大部分垃圾收集器对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间。
而由于老年代的特点是每次回收都只回收少量对象,一般使用的是Mark-Compact算法。

3.Mark-Compact(标记-整理)算法
为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。

4.Generational Collection(分代收集)算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。

垃圾回收器

新生代垃圾收集器有Serial、ParNew、Parallel Scavenge,G1,属于老年代的垃圾收集器有CMS、Serial Old、Parallel Old和G1.其中的G1是一种既可以对新生代对象也可以对老年代对象进行回收的垃圾收集器。然而,在所有的垃圾收集器中,并没有一种普遍使用的垃圾收集器。在不同的场景下,每种垃圾收集器有各自的优势,如下图:
垃圾回收器
Serial收集器
Serial是最基本也是发展最悠久的收集器。它是一种单线程垃圾收集器,这就意味着在其进行垃圾收集的时候需要暂停其他的线程

ParNew收集器:
可以把这个收集器理解为Serial收集器的多线程版本,由于存在线程切换的开销,ParNew在单CPU的环境中比不上Serial,在通过超线程技术实现的两个CPU的环境中也不能100%保证能超越Serial. 但随着可用的CPU数量的增加, 收集效率肯定也会大大增加。

Parallel收集器:
Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。区别在于Parallel Scavenge收集器更关注可控制的吞吐量,

吞吐量 = 运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)。

这个参数有什么意义呢?根据数据知识,吞吐量越大,意味着垃圾收集的时间越短,则用户代码则可以充分利用CPU资源,尽快完成程序的运算任务。Parallel Scavenge收集器使用两个参数控制吞吐量:
-XX:MaxGCPauseMillis控制最大的垃圾收集停顿时间,
-XX:GCRatio直接设置吞吐量的大小。
直观上,只要最大的垃圾收集停顿时间越小,吞吐量是越高的,但是GC停顿时间的缩短是以牺牲吞吐量和新生代空间作为代价的。比如原来10秒收集一次,每次停顿100毫秒,现在变成5秒收集一次,每次停顿70毫秒。停顿时间下降的同时,吞吐量也下降了。

Serial Old收集器
Serial Old收集器是Serial收集器的老年代版本,也是一个单线程收集器,采用“标记-整理算法”进行回收。其运行过程与Serial收集器一样。

Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法进行垃圾回收。通常与Parallel Scavenge收集器配合使用,“吞吐量优先”收集器是这个组合的特点,在注重吞吐量和CPU资源敏感的场合,都可以使用这个组合。

CMS收集器
是一种获取最短停顿时间为目标的收集器,基于标记清除(老年代唯一一个基于标记清除的算法,除G1外)的算法实现。整个过程有四个步骤,初始标记,并发标记,重新标记,并发清除,其中初始标记与重新标记要停顿所有用户线程。初始阶段主要负责标记gcroot能直接关联的对象,速度很快,并发标记是从gc root开始继续向下进行标记,重新标记是统计那些并发标记的过程中发生变化的标记,这个阶段的时间要比初始标记长,但是低于并发标记。并发清除是清除老年代中的垃圾。CMS存在缺点:1.采用标记清除(老年代唯一一个采用标记清除的算法)的算法会产生碎片。2.不能处理浮动垃圾(浮动垃圾:在并发清除时,用户线程还在运行,还会有新的垃圾产生,这部分只能等到下次GC时清理)3.对CPU特别敏感。由于CMS在GC时最耗时的并发标记和并发清除是与用户线程同时执行的,因此可以降低停顿时间。但是并发标记时会占用一部分的CPU资源,导致应用程序变慢。

G1收集器
唯一一个可以同时用于年轻代和老年代的垃圾收集器。G1收集器采用标记整理的算法避免碎片。使用该收集器时,其堆的内存布局就发生变化,将被分为不同大小相等的region,G1追踪每个region的垃圾堆积的价值大小,然后有一个优先列表,优先回收价值最大的region(每个region有一个remembered Set,为了避免做可达性分析是扫描这个堆,当引用在不同的region之间,则将相关引用信息记录到remember Set中),避免在整个堆中进行全区域的垃圾收集,能建立预测的停顿时间模型,整个过程包含如下四个步骤,初始标记,并发标记,最终标记,筛选回收。初始标记与并发标记与CMS相似。最终标记将并发标记阶段那些发生变化的对象的变化记录写入到线程 remembered Set log,同时与remembered Set 合并。筛选回收阶段:通过对每个region的价值和成本进行筛选,以得到一个最好的回收方案,并回收。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值