读《深入理解Java虚拟机》-垃圾收集器

Serial收集器

这是一个单线程收集器,在垃圾收集的时候会暂停其他的工作线程,美其名曰:Stop The World。停止其他线程的动作是jvm自动发起的,在用户不知道的情况下中断用户的工作线程。
优点是简单而高效 因为他是单线程工作,专心收集垃圾,没有线程的切换等开销,对于运行在client模式下的虚拟机(新生代空间不会过大)来说,停顿100多毫秒内是可以接受的。
Serial收集器

ParNew收集器

ParNew收集器是Serial的多线程版本,没有什么创新之处。但是因为只有它和Serial能和CMS收集器配合使用,所以它经常被用作Server模式下新生代的收集器。算是榜上一个大款。。。
参数:
-XX:+UseConcMarkSweepGC 默认新生代收集器
-XX:+UseParNewGC 强制指定作为新生代收集器

ParNew收集器

Parallel Scavenge收集器

这个收集器同样使用复制算法,也是多线程模式,看起来和上面的ParNew差不多,它关注的点是控制垃圾收集的程序的吞吐量。高吞吐量就可以高效率的利用CPU时间,尽快完成程序的运算任务。适合后台运算而不需要太多交互的任务。
参数:
-XX:MaxGCPauseMillis 最大垃圾收集停顿时间
-XX:GCTimeRadio 设置吞吐量大小,取值(1,100)
-XX:UseAdaptiveSizePolicy 开关参数,打开后自动调节jvm各个内存区域大小和比例。(GC自适应调节策略)
MaxGCPauseMillis参数让收集器尽可能的回收一次耗费的时间不超过设定值,但是如果把这个值设置的越小,虽然每次收集时间变短,但是收集的频率会变高,所以是牺牲了吞吐量和新生代的空间。
GCTimeRadio参数是垃圾收集时间占总时间的比例,相当于吞吐量的倒数,默认值是99,就是允许最大1%(即1/(1+99))的垃圾收集时间。如果是19,那就是1/(1+19)=5%,也就是垃圾收集时间最大占5%的时间。

Serial Old收集器

这是Serial的老年代版本,同样是单线程模式,使用标志-整理算法,同样给Client模式下的jvm用。要是在Server模式下,能够与Parallel Scavenge收集器搭配使用,另外可以作为CMS的备胎,在并发收集器发生Concurrent Mode failure时使用。
在这里插入图片描述

Parallel Old收集器

这是Parallel Scavenge的老年代版本,使用多线程和标志-整理算法。与Parallel Scavenge搭配能够提高CPU资源使用率和吞吐量。

Parallel Old收集器

CMS收集器

CMS收集器能够使得回收停顿时间最短,一般在server模式下使用,采用标记-清楚算法,整个运作过程分为4个步骤:

  1. 初始标记 标记一下GC Roots能直接关联的对象,速度很快,需要stop the world。
  2. 并发标记 进行GC Roots Tracing的过程,追踪引用链。因为时间相对较长,所以没有stop the world
  3. 重新标记 修正并发标记阶段因用户线程继续工作而导致标记产生变动的那一部分对象的标记记录。时间比初始标记稍长,但是远短于并发标记。
  4. 并发清除 根据标记-清除算法回收被标记的对象。

缺点

  1. 对CPU资源非常敏感 在并发时,CMS收集器会占有一部分CPU资源标记和清楚对象,那么势必会影响工作线程的,导致吞吐量下降。CMS默认启动的线程数是(CPU数量+3)/4.
  2. 无法处理浮动垃圾 可能出现Concurrent Mode Failure失败而导致另一次Full GC的产生。在CMS并发清理阶段,工作线程还在持续的产生垃圾,这些垃圾就叫浮动垃圾。因为是出现在标记之后,所以CMS肯定无法处理,只能留到下一次GC处理。在回收垃圾时还要预留一部分内存给工作线程用,所以不能等老年代填满了才进行收集,可以通过参数-XX:CMSInitiatingOccupancyFraction的值来提高触发百分比,以便降低回收次数,提升性能。要是CMS在垃圾收集期间预留的内存无法满足允许的线程需要,就会发生Concurrent Mode failure失败,这时虚拟机将启动备胎Serial Old,重新进行老年代的垃圾回收,这样停顿的时间就有点久了,所以-XX:CMSInitiatingOccupancyFraction不能设置太高。
  3. 标记-清除算法产生内存碎片 会对大对象的分配带来麻烦,明明老年代的空间还很多,但是就是没有一个足够大的连续空间来存储新的大对象,这个时候不得不触发一次full gc,为了解决这个问题,CMS有个开关参数叫-XX:CMSCompactAtFullCollection,用于在马上要进行full gc了去合并整理内存碎片,内存整理的过程是无法并发的,空间碎片被整理完,但是等待的时间也长了。所以还提供了一个参数叫 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置执行多少次不压缩的FullGC后,跟着来一次带压缩的。

CMS收集器

G1收集器

G1收集器把jvm的内存区域划分为一个一个独立的region,虽然还保留着分代的概念,但是新生代和老年代不再是物理上的隔离,它们是多个region的集合。收集步骤基本和CMS类似:

  1. 初始标记 就是标记直接和GC Roots关联的对象,需要停顿工作线程
  2. 并发标记 寻找GC Roots的引用链,也就是可达性分析,找存活对象。并且此时region里面还可以创建新的对象,并且把对象的变化记录到Remembered Set Logs里面
  3. 最终标记 就是修正在并发标记阶段状态变化的对象,并把Remembered Set Logs合并到Remembered Set。需要停顿线程。
  4. 筛选回收 先对各个region的回收价值和成本排序,根据用户期望的GC停顿时间来制定回收计划。

特点:

  1. 并行与并发 主要就是利用多CPU和多核,缩短了stop the world时间
  2. 分代收集 使用region的方式来处理新创建和存活一段时间的,熬过多次GC的对象。
  3. 空间整合 G1从整体上看采用的是标记-整理算法,从局部看是复制算法,这两种算法都是为了让内存更加规整,不容易产生内存碎片。
  4. 可预测的停顿 除了追求更短的停顿时间,G1收集器还可以指定在一个长度为M毫秒内,消耗在gc的时间不超过N毫秒。

G1之所以能够预测gc停顿的时间,是因为它有计划的避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个region里面垃圾堆积的价值大小(回收所获的空间大小与回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间来回收价值最大的 region。这样使用region划分空间以及按照价值优先级区域回收,保证了G1在有限的时间内回收效率尽可能高。
另外一个问题是在找GC Roots引用链的时候,如果一个region里面的对象被其他region里面的引用了,那么是不是也要扫描所有的region,也就是全堆扫描?G1通过使用Remembered Set来避免全堆扫描,每个region都有一个对应的Remembered Set,虚拟机发现在对Reference类型的数据写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是不是在另外一个region,如果是,就把引用信息记录到被引用对象的所属Region的Remembered Set。这样在gc时,在根结点的枚举范围中加入Remembered Set就可以保证不进行全堆扫描也不会遗漏了。
G1收集器

总结
最后列出各个收集器的搭配使用关系
垃圾收集器搭配

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值