聊聊JVM垃圾回收器

今天,我们一起看一下JVM的垃圾回收器。

垃圾回收器组合

垃圾回收器是在堆区进行回收,堆区分为新生代老年代,不同区域由于生成/淘汰对象的频率,使用不同的垃圾回收器。主要有以下几种组合:

  • Serial+Serial Old
    Serial + Serial Old 这种组合现在基本不用了。因为以前内存小的时候,这种垃圾回收不会消耗很长时间。但是随着内存越来越大,才诞生了各种各样不同的垃圾回收器,来管理越来越大的大内存。
  • ParNew+CMS
  • Parallel Scavenge+Parallel Old
    回收效率:10G内存的话,PS+PO,回收一次要十几秒
    在这里插入图片描述

各垃圾回收器

新生代

先来说说新生代使用的几种垃圾回收器吧!
他们的共同点:均使用复制算法进行垃圾回收

1. Serial GC (单线程GC)

Serial 是一个 stop-the-world(STW)。
垃圾回收时,工作线程全停止,等着垃圾回收线程进行回收,这时候用户是得不到任何反馈的。(耗时较长的垃圾回收耗费大约几十秒~1分钟)。

-XX:+UseSerialGC      设置新生代使用Serial GC
SafePoint

safe point 含义是在程序运行到安全点上的时候再STW,而不是立刻停止。
比如:解锁操作完成之后再停止,然后进行垃圾回收。
在这里插入图片描述

-XX:+UseSerialGC   使用命令

2. ParNew GC (多线程版的Serial GC)

默认线程数与CPU数量相同。可通过-XX:ParallelGCThreads来设置线程数,同样存在STW问题。

在这里插入图片描述

-XX:+UsePerNewGC            使用命令

3. Parallal Scaverage GC

它是多线程的STW垃圾回收器,多个线程共同并行回收。
注意
Parallel Scavenge是并行,不是并发。
CMS是并发,回收线程和工作线程同时进行。
但随着内存越来越大,线程数越来越多,CPU会将资源耗费在线程切换上,因此线程数不可被无限增多。
在这里插入图片描述

吞吐量

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

相关指令
-XX:+UseParallelGC          可以设置新生代使用这个并行回收器
-XX:+UseAdaptiveSizePolicy  打开自适应模式,在这种模式下,新生代的大小、eden、from/to的比例,以及晋升老年代的对象年龄参数会被自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点。
-XX:MaxGCPauseMillis        设置最大垃圾收集停顿时间。可用把虚拟机在GC停顿的时间控制在MaxGCPauseMillis范围内,将MaxGCPauseMillis设置的很小,可以减少GC停顿时间,但是会导致GC频繁,从而增加了GC的总时间,降低了吞吐量。所以需要根据实际情况设置该值。
-XX:GCTimeRatio             设置吞吐量大小,它是一个0到100之间的整数,默认情况下他的取值是99,那么系统将花费不超过1/(1+n)的时间用于垃圾回收,也就是1/(1+99)=1%的时间。

老年代

下面介绍一下老年代的几种垃圾回收器

1. Serial Old GC 标记整理(压缩)算法

SerialOld是Serial回收器的老年代回收器版本,它同样是一个单线程回收器。使用标记整理(压缩)算法
作为CMS收集器的后备预案,如果CMS出现Concurrent Mode Failure,则SerialOld将作为后备收集器。

在这里插入图片描述

2. Parallal Old GC 标记整理(压缩)算法

ParallelOldGC回收器是一种多线程的回收器,和新生代的ParallelGC回收器一样,关注吞吐量的回收器。使用标记整理(压缩)算法
在这里插入图片描述

-XX:+UseParallelOldGC  设置老年代使用该回收器
-XX:+ParallelGCThreads 设置垃圾收集时的线程数量。

3. CMS GC 标记清除算法

全称:Concurency Mark Swap GC,即并发标记清除GC,使用标记清除算法
特点

  • 它在进行垃圾回收时并不会停止其他线程,垃圾回收和应用程序同时运行,降低STW的时间(200ms)。
  • 通过阈值来触发垃圾回收,默认值是68%,即老年区被使用68%时,开始垃圾回收。回收阀值可通过XX:CMSInitiatingoccupancyFraction来指定。
  • CMS既然是MarkSweep,就一定会有碎片化的问题。碎片到达一定程度内存使用率增长的很快,在CMS执行的过程中,已经出现了内存不足的情况,此时CMS回收就会失败,虚拟机将启动老年代串行回收器SerialOldGC进行垃圾回收,这会导致应用程序中断,直到垃圾回收完成后才会正常工作。
    在这里插入图片描述
流程

CMS 分为4个阶段
初始标记:需要STW,因为初始的垃圾并不多,因此耗费的时间不长;
并发标记:垃圾回收线程和工作线程同时执行。一边产生垃圾,一边标记
重新标记:对在并发标记的过程中新产生的垃圾进行重新标记,或者原来被标记的垃圾变为不是垃圾。因为新产生的垃圾不多,所以时间也不是很长;
并发清理:清理的过程也会产生新的垃圾“浮动垃圾”,需要等下一次CMS重新运行的时候再次清理。

CMS的问题
  • Memory Fragmentation 内存碎片问题: 因为标记清除会产生碎片化,如果老年代已经没有地方可以装了,CMS会请出Serial Old让它来进行清理,Serial Old是单线程的,效率很低。
-XX:+UseCMSCompactAtFullCollection      可以使CMS回收完成之后进行一次碎片整理
-XX:CMSFullGCsBeforeCompaction          默认为0 设置经过多少次FGC才进行压缩
  • Floating Garbage 浮动垃圾问题:老年代满了,浮动垃圾没有清理完。这时会请出Serial Old让它来进行清理

Concurrent Mode Failure
产生:if the concurrent collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped
这个现象在日志里打印出来是PromotionFailed

解决方案

以上两个问题的解决方案类似:降低触发CMS的阈值,保持老年代有足够的空间。
–XX:CMSInitiatingOccupancyFraction 92 可以理解为,老年代内存到达92% 的时候,CMS才工作。
可以降低这个值,让CMS保持老年代足够的空间。
可以使用命令查看默认值:

java -XX:+PrintFlagsFinal -version | grep CMSInitiatingOccupancyFraction
相关指令
-XX:+UseConcMarkSweepGC            设置老年代使用该回收器。
-XX:+UseCMSCompactAtFullCollecion  可以使CMS回收完成之后进行一次碎片整理
-XX:CMSFullGCsBeforeCompaction     默认为0 设置经过多少次FGC才进行压缩
-XX:ConcGCThreads                  设置并发线程数量。

G1

G1是逻辑分代物理不分代(物理分代就是内存里确实有这样一块空间)


欢迎大家评论,如果本文对您有帮助,请点个赞,您的点赞对我很重要!这次一定!感谢!!!
转发请注明出处呦!感谢!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.Letian

您的打赏是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值