JVM垃圾收集器

JVM中垃圾的回收由垃圾收集器进行,每种收集器采用的回收算法不同(标记-清除算法、复制算法、标记-整理算法, 分代收集算法实际是这三个算法在不同代中的使用),随着JDK的不断升级,垃圾收集器也开发出了各种版本,垃圾收集器不断优化的动力,就是为了实现更短的停顿(所有收集器都涉及Stop the world,暂停所有用户线程)。

下面是7种不同的收集器,如果两个收集器之间有连线,则表示它们之间可以搭配使用;所处的区域表示属于新生代还是老年代收集器。

在这里插入图片描述

一.Serial 收集器 --串行收集器

最基本、发展历史最久的收集器,这个收集器是一个采用复制算法的单线程的收集器。只使用一个单独的线程进行垃圾回收,通过冻结所有应用程序线程进行工作,所以可能不适合服务器环境。它最适合的是简单的命令行程序。

“单线程”说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。

参数:通过JVM参数 -XX:+UseSerialGC可以使用串行垃圾回收器。
在这里插入图片描述
上图中,新生代采用Serial 收集器,老年代采用 Serial Old 收集器
作用区域: 新生代,红框圈起来的部分就是Serial 收集器的工作区域和机制

收集过程:暂停所有用户线程(Stop the world)

算法:复制算法

优点:简单高效,拥有很高的单线程收集效率

应用:Client模式下的默认新生代收集器
这实际很好理解,你在清扫垃圾的时候,总不希望有人同时在丢垃圾吧。

二.ParNew 收集器 (新生代)

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集外,其余行为和Serial收集器完全一样,包括使用的也是复制算法。

ParNew收集器除了多线程以外和Serial收集器并没有太多创新的地方,但是它却是Server模式下的虚拟机首选的新生代收集器,其中有一个很重要的和性能无关的原因是,除了Serial收集器外,目前只有它能与CMS收集器配合工作。CMS收集器是一款几乎可以认为有划时代意义的垃圾收集器,因为它第一次实现了让垃圾收集线程与用户线程基本上同时工作。ParNew收集器在单CPU的环境中绝对不会有比Serial收集器更好的效果,甚至由于线程交互的开销,该收集器在两个CPU的环境中都不能百分之百保证可以超越Serial收集器。当然,随着可用CPU数量的增加,它对于GC时系统资源的有效利用还是很有好处的。它默认开启的收集线程数与CPU数量相同,在CPU数量非常多的情况下,可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。
在这里插入图片描述
上图中,新生代采用ParNew 收集器,老年代采用 Serial Old 收集器
作用区域: 新生代,红框圈起来的部分就是ParNew 收集器的工作区域和机制
收集过程:(Stop the world)

算法:复制算法

优点:在CPU多的情况下,拥有比Serial更好的效果。单CPU环境下Serial效果更好

应用:许多运行在Server模式下的虚拟机中首选的新生代收集器
参数控制:
-XX:+UseParNewGC ParNew收集器
-XX:ParallelGCThreads 限制线程数量

三.Parallel Scavenge 收集器(新生代)

Parallel Scavenge收集器的目标是达到一个可控制的吞吐量

吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
Parallel Scavenge收集器也是一个新生代收集器,也是用复制算法的收集器,也是并行的多线程收集器,但是它的特点是它的关注点和其他收集器不同。

CMS等收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。

介绍这个收集器主要还是介绍吞吐量的概念。所谓吞吐量的意思就是CPU用于运行用户代码时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),虚拟机总运行100分钟,垃圾收集1分钟,那吞吐量就是99%。

另外,Parallel Scavenge收集器是虚拟机运行在Server模式下的默认垃圾收集器。

停顿时间短适合需要与用户交互的程序,良好的响应速度能提升用户体验;高吞吐量则可以高效率利用CPU时间,尽快完成运算任务,主要适合在后台运算而不需要太多交互的任务。虚拟机提供了-XX:MaxGCPauseMillis和-XX:GCTimeRatio两个参数来精确控制最大垃圾收集停顿时间和吞吐量大小。不过不要以为前者越小越好,GC停顿时间的缩短是以牺牲吞吐量和新生代空间换取的。由于与吞吐量关系密切,Parallel Scavenge收集器也被称为“吞吐量优先收集器”。Parallel Scavenge收集器有一个-XX:+UseAdaptiveSizePolicy参数,这是一个开关参数,这个参数打开之后,就不需要手动指定新生代大小、Eden区和Survivor参数等细节参数了,虚拟机会根据当前系统的运行情况性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。如果对于垃圾收集器运作原理不太了解,以至于在优化比较困难的时候,使用Parallel Scavenge收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个不错的选择。
在这里插入图片描述
在这里插入图片描述
作用区域: 新生代,红框圈起来的部分就是Parallel Scavenge收集器的工作区域和机制
上图中,新生代采用Parallel Scavenge收集器,老年代采用 Parallel Old 收集器
控制吞吐量的参数:最大垃圾收集停顿时间 -XX:MaxGCPauseMillis ; 直接设置吞吐量大小:-XX:GCTimeRatio。

MaxGCPauseMillis 的值为一个大于0的毫秒数, 最大停顿时间的缩短是以牺牲吞吐量和新生代空间来换取的。

GCTimeRatio 的值为一个大于0且小于100的整数。例如:-XX:GCTimeRatio=9 我们要求应用程序线程在整个执行时间中至少9/10是活动的(因此,GC线程占用其余1/10)

-XX:+UseAdaptiveSizePolicy:开启GC自适应调节策略,自动设置新生代大小、Eden与Survior区的比例、晋升老年代对象年龄等细节参数

应用:适合在后台运算而不需要太多交互的任务

四.Serial Old 收集器

Serial收集器的老年代版本,也是一个单线程的收集器,使用标记-整理算法
作用区域:老年代,红框圈起来的部分就是Serial Old收集器的工作区域和机制
在这里插入图片描述
上图中,新生代采用Serial 收集器,老年代采用 Serial Old 收集器
收集过程:暂停所有线程,(Stop the world)

算法:标记-整理算法

应用:主要意义是Client模式下的收集器,如果在Server模式下还有:a. JDK1.5之前的版本中与Parallel Scavenge搭配使用,b. 作为CMS收集器的后背预案在并发收集时使用

五. Parallel Old 收集器 (老年代)

Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。

这个收集器是在JDK1.6中才开始提供的,在此之前,新生代的Parallel Scavenge收集器一直处于比较尴尬的状态。原因是新生代如果选择了Parallel Scavenge收集器,老年代除了Serial Old收集器别无选择(因为它无法与CMS配合使用)。

在多CPU时代,由于Serial Old收集器在服务端性能上的“拖累”,使用了Parallel Scavenge收集器也未必能在整体应用上获得吞吐量最大化的效果。直到Parallel Old收集器的出现后,“吞吐量优先”收集器才有了比较名副其实的应用组合。在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器
作用区域: 老年代,红框圈起来的部分就是Parallel Old收集器的工作区域和机制

在这里插入图片描述
上图中,新生代采用Parallel Scavenge收集器,老年代采用 Parallel Old 收集器
收集过程:多线程,(Stop the world)

算法:标记-整理算法

应用:在注重吞吐量及CPU资源敏感的场合,可以优先考虑Parallel Scavenge加Parallel Old收集器

六、CMS 收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用。

CMS(Concurrent Mark Sweep)收集器是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。

从名字中的Mark Sweep这两个词可以看出,CMS收集器是一种 “标记-清除”算法实现的,Concurrent 并发,老年代收集器,它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤:

初始标记: 暂停所有的其他线程,并记录下GC Roots能直接关联到的对象,速度很快 ;需要“Stop The World”(标记GC ROOTS 以及GC ROOTS直接引用的对象), 如果还要标记后面的引用对象,速度就会很慢了,停顿时间长
在这里插入图片描述
并发标记: 同时开启GC和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以GC线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。标记初始标记子节点后面未扫描的节点
在这里插入图片描述
重新标记: 重新标记阶段就是为了修正并发标记期间,因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短。仍然需要“Stop The World”

并发清除: 开启用户线程,同时GC线程开始对未标记的区域做清扫。
在这里插入图片描述
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行。
从它的名字就可以看出它是一款优秀的垃圾收集器,主要优点:并发收集、低停顿。但是还远达不到的完美程度,它有以下3个明显缺点:

1.CMS收集器对CPU资源非常敏感。

因为在并发阶段,它会占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量会降低。

2.CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。

由于CMS并发清理阶段用户线程还在运行着,伴随着程序运行自然就还会有新的垃圾不断产生,这部分垃圾出现在标记过程之后,CMS无法在当次收集中处理它们,只好留待在下一次GC时再清理掉,这一部分垃圾就称为“浮动垃圾”。
在并发清理阶段,如果有些原来标记为不可达的对象,重新被引用关联,则该对象不会被清理,具体实现由cms机制保障,不做详细研究。

3.还有最后一点,CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量的空间碎片产生。

为了解决这个问题,CMS收集器提供了一个-XX:+UseCMSCompactAtFullColletion开关参数(默认是开启的),用于在CMS收集器顶不住要进行Full GC时开启内存碎片合并整理过程,内存整理的过程是无法并发的,空间的碎片问题没有了,但停顿的时间不得不变长了。虚拟机设计者还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,表示每次进入Full GC时都进行碎片整理)。
参数控制:

-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理
-XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量)

七、G1 收集器

https://zhuanlan.zhihu.com/p/32820815
https://blog.csdn.net/baiye_xing/article/details/73743395
http://www.ityouknow.com/jvm/2017/08/29/GC-garbage-collection.html

八、总结

虽然我们是在对各个收集器进行比较,但并非为了挑选出一个最好的收集器。因为直到现在为止还没有最好的收集器出现,更加没有万能的收集器,所以我们选择的只是对具体应用最合适的收集器。这点不需要多加解释就能证明:如果有一种放之四海皆准、任何场景下都适用的完美收集器存在,那HotSpot虚拟机就没必要实现那么多不同的收集器了。

文章:
https://www.cnblogs.com/study-everyday/p/7066823.html
https://blog.csdn.net/striveb/article/details/86101054
http://www.ityouknow.com/jvm/2017/08/29/GC-garbage-collection.html
https://www.jianshu.com/p/50d5c88b272d

分配和回收
https://blog.csdn.net/fxkcsdn/article/details/81435749
https://blog.csdn.net/v123411739/article/details/78941793

gc日志:
https://blog.csdn.net/lan861698789/article/details/51985188
https://www.jianshu.com/p/fd1d4f21733a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值