简述垃圾收集器


之前介绍过 jvm中的垃圾算法,算法只是我们将无效对象回收的一种方式,最终将这些算法运用起来的,是 垃圾收集器,随着java应用的业务场景越来越多,java在不停的版本迭代过程中,推出了很多中垃圾收集器,来应对不同的业务以及服务场景。

Stop The World

在介绍GC收集器之前,先介绍一个在了解GC回收过程中必要的一个概念,就是全线暂停。想象一下,我们在GC的过程中,除了已经存在的垃圾对象,还有很多新的垃圾对象产生,想要在程序运行的过程中,去彻底的回收所有垃圾,几乎是不太可能的,所以GC收集器就产生了这样的一个动作,就是先将应用的其他线程都挂起,全量去进行GC操作,操作完毕之后释放,这个动作就是我们提到的Stop The World,这个动作的重要性其实是,在这段时间里我们程序的其他的操作都无法进行,在某些场景还可以接受,对于一些特殊场景,延迟低是必须的,这对于我们的停顿时间的要求是非常高的,所以在越来越新版本的GC收集器中,对于Stop The World时间的管理,都会有不同的做法。我们对Stop The World 简称为STW

各种收集器介绍

Serial GC

首先介绍的是串行GC,Serial GC分为Serial GCSerial Old GC,他们一个是新生代的版本,一个是老年代的版本,这个是java早期推出的第一个垃圾收集器,顾名思义,串行GC的意思是说,GC的过程都是单线程的。单线程场景下的GC,而且还需要STW之后进行,那这个体验想想是不是就很难受,垃圾少还可以,稍微多一些,那么GC的时间又长,SWT的时间又长,所以串行GC的使用一般可以放在服务器资源有限制,并且限制特别低的场景下使用

必知必会
  1. 使用-XX:+UseSerialGC将应用设置为串行GC, 设置之后默认同时使用Serial GCSerial Old GC
  2. 串行GC对年轻代使用的是标记复制算法,老年代使用的是标记整理算法
  3. 因为是串行执行GC,所以不论是年轻代还是老年代都是串行,过程中会全线STW
  4. 哪怕是在多核CPU的情况下指定串行GC,那也是只能用到一个核

ParNew GC

这个收集器是Serial GC的升级版,除了将串行GC改为多线程GC,其他的几乎没有任何变化。明显的提升肯定是GC的时间变短,STW的时间肯定也会相应的变短

必知必会
  1. 使用-XX:+UseParNewGC将应用设置为ParNew GC,但是注意一下,这个只针对与新生代设置,设置了之后,老年代还是默认用的串行GC
  2. 可以使用-XX:ParallelGCThreads来设置并行处理GC过程中的线程数,默认和逻辑CPU数一样,这样可以最大化利用资源
  3. 这个设置只作用于新生代,可以使用CMS GC配合使用,因为CMS GC是只作用于老年代的GC,而且,目前来说,只有parnew 能和CMS GC配合使用,为什么呢? 其实是因为框架问题,其他的新收集器都是用的其他框架,没办法配合CMS,只有ParNew GC和CMS GC使用的是同一套

Parallel GC

并行GC也是分为Parallel ScavengeParallel Old,他们一个是新生代的版本,一个是老年代的版本,他们也是多线程执行GC,新生代使用的是标记复制,老年代使用的是标记整理,和ParNew GC比较像,但是Parallel GC的主要关注点是系统的吞吐量,所以使用Parallel GC,更好的地方是我们可以通过参数去控制应用的吞吐量,一般适合多任务,但是少交互的场景

必知必会
  1. 并行GC可以分开指定新生代和老年代GC的收集器-XX:+UseParallelGC -XX:+UseParallelOldGC,默认的话新老代都是并行GC
  2. 也可以使用-XX:ParallelGCThreads来设置并行处理GC过程中的线程数
  3. -XX:MaxGCPauseMillis可以用来指定最大STW的时间
  4. -XX:GCTimeRatio可以控制吞吐量
  5. -XX:+UseAdptiveSizePolicy 可以开启让GC收集器自行调整参数来最大化的提供最合适的吞吐量和GC停顿时间
  6. 并行GC,STW的时间长,但是GC的效率高

CMS GC

CMS GC的全名是ConcMarkSweepGC,它是老年代的一个收集器,设置以后默认配合ParNew新生代GC进行使用,这个收集器最重要的控制的点就是要尽可能小的减少STW的时间,从而减少系统的延迟。它将GC的过程分成了不同的几个阶段,操作最快的阶段是STW之后进行的,其他耗时的操作大部分都是跟应用线程并发完成,也就是说,它的很多工作都是在系统运行的时候,并发的处理的,这样的做法,牺牲了完整GC之后的高效,但是保证了应用最短的STW时间,适合低延迟的场景,保证用户的使用

GC的几个阶段分为

  1. 初始标记(STW)
  2. 并发标记
  3. 并发预清理
  4. 最终标记(STW)
  5. 并发清除
  6. 并发重置
必知必会
  1. CMS GC只针对老年代进行处理,通过-XX:+UseConcMarkSweepGC进行指定,指定之后,新生代默认就会使用ParNew GC收集器
  2. CMS GC老年代并不是使用的标记整理,而是使用的标记清除,会产生很多的内存碎片,堆内存越大,碎片空间越多,会导致后续去存放大对象的时候比较困难,要注意这个问题的解决
  3. CMS GC暂停的时间短,但是GC的代价大
  4. 默认使用4/1的线程数去进行GC
  5. 很复杂

G1 GC

G1 GC的全名是 Garbage-First,他的很多概念都是基于CMS GC做基础,G1 GC不再简单的分为年轻代和老年代去回收对象,而是把年轻代和老年代分成了若干个年轻代和老年代,一般是 2048 个,他会去评估哪个小块的垃圾数量多,多的小块会优先被回收,可以用来替换CMS GC,它可以同时保证STW和吞吐量的平衡,将STW停顿的时间和分部,变成可预期并且可以配置的,它会根据我们配置的参数去评估要回收的垃圾数量,可能每次会多回收一些,可能会少回收一些,优先保证我们配置的预期参数

必知必会
  1. -XX:+UseG1GC 来使用G1GC
  2. G1GC默认的回收时机是内存空间到达45%之后进行,G1GC之前的那些都是对象太大,或者内存不够的时候才触发

能力有限,G1GC了解不是很深,所以只能简单的介绍一些个人理解,具体内容感兴趣可以去深入了解

ZGC

没有用过。。。

如何选择?

对于什么时候用哪个垃圾收集器,其实主要看我们应用的场景以及垃圾收集器的特性来对应的

  1. 资源有限,cpu单核,串行GC没的说
  2. 跑一些后台应用,需要高吞吐的场景,可以使用java8默认并行GC
  3. 比如用户服务端,需要提升体验的应用,减少延迟,可以用CMS GC+ ParNew GC组合使用(默认也是组合)
  4. 但是一般如果我们服务器内存都比较大了,可以用CMS的话,不如直接升级稳定版本的G1GC, ps: 肯定是新的更好嘛

总结

这片文章主要简单介绍了一下目前个人接触比较多的GC收集器,因为能力以及篇幅有限,没办法每个都讲的特别细,了解了这些垃圾收集器,可以实际的去考虑哪种收集器更适合我们现在用的场景,做一些简单的优化

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值