jvm垃圾收集器你学废了吗(一)

前言

前面一篇文章讲了垃圾回收的算法(传送门),今天来说一下从古到今一些经典的垃圾收集器,直接进入正题!

Serial 收集器

Serial 收集器也算上是一个老古董了,看到这个名字,我们就可以猜到这是一个单线程工作的收集器,采用的是标记-复制算法,这里的单线程不仅说它使用一个处理器或者一条线程,而是它必须暂停其他所有工作的线程,Stop The World 这个世界都暂停了,可想而知,你的电脑说不定在某个时刻就要暂停下来等待垃圾回收,这是多么糟糕的一件事情!
在这里插入图片描述
但是它依然是HotSpot虚拟机运行在客户端模式下的默认新生代收集器,这时候问题来了 什么是客户端模式呢,是不是还有服务器模式呢
如果是64位的jdk,只能运行在Server模式下。而32位的jdk,默认是运行在client模式下,可以通过修改设置来指定默认的启动模式。
还可以通过在cmd命令行窗口用 java -version 查看
在这里插入图片描述

优点

  • 简单而高效
  • 没有其他的内存消耗,所以说内存消耗小

缺点就不用我多说了吧

ParNew 收集器

ParNew 收集器实质上是Serial收集器的多线程版本,这里讲的多线程是多个垃圾收集的线程,采用的是标记-复制算法,并不是垃圾收集线程和用户线程并行,它也是用于新生代的收集器,相比Serial 并没有太多的创新,之后或说到一个CMS收集器,它的出现让ParNew 又活了一段时间,CMS作为老年代的收集器,ParNew 作为新生代的收集器。
但是好景不长,随着技术的日益发展,G1收集器的出现让ParNew彻底的退出了历史舞台(后面都会介绍)
在这里插入图片描述

优点

  • 在多核处理器上,ParNew收集器对系统资源的高效利用还是很有好处的

缺点

  • 在单核处理器上ParNew的效果远不及Serial收集器,因为存在线程交互的开销

Parallel Scavenge 收集器

Parallel Scavenge 收集器也是一款新生代的垃圾收集器,同样采用标记-复制算法,很多地方都和ParNew 收集器神似。但是它有它的独特之处!
在这里插入图片描述
Parallel Scavenge 收集器目标是一个可控制的吞吐量,这时候问题来了 什么是吞吐量呢
吞吐量就是处理器运行代码的时间和处理器使用的总时间的比值,Parallel Scavenge 收集器提供了两个参数:

  • -XX:MaxGCPauseMillis 控制最大垃圾收集的停顿时间
    参数值 是一个大于0的毫秒数,收集器在每次垃圾回收的时间不是超过这个值,不过大家不用以为把这个值调到很小,这样垃圾回收的效率就高了,这个想法是错误的,它牺牲了吞吐量和新生代的空间,比如说收集50M的空间肯定比收集100M的空间速度要快,之前10秒收集一次,每次需要100毫秒,现在3秒收集一次,每次耗时40毫秒,这会使垃圾回收的次数频繁,所以这个值一定要设置的合理
  • -XX:GCTimeRatio 直接设置吞吐量的大小
    参数值是大于0小于100的整数,比如我们设置19,允许垃圾回收的时间占总时间的5% (1/(1+19)),默认值是99 也就是垃圾回收的时间在总时间的1%

优点

  • Parallel Scavenge 收集器的优点就是它提供了一个-XX:+UseAdaptiveSizePolicy的一个参数,这是一个开关参数,如果它被激活了,就不需要人工的指定新生代、Eden、Survivor区域的大小、晋升老年代对象的大小等细节参数,虚拟机会个根据当前系统的运行情况提供最合适的策略

缺点

  • Stop The World

Serial Old 收集器

Serial Old 收集器是Serial 老年代版本,同样也是单线程收集器, 使用标记-整理算法, 这个收集器和Serial 基本一样,这里就不做阐述,它与Parallel Scavenge收集器配合使用

Parallel Old 收集器

Parallel Old 收集器,这个收集器说来也是尴尬,他是Parallel Scavenge 收集器的老年代版本,支持多线程并发收集,也是基于标记-整理算法,在早期Parallel Scavenge 收集作为新生代的垃圾收集器,它只能选择Serial Old作为老年代的垃圾收集器,没有别的选择,但是由於单线程的老年代收集无法充分利用服务器多处理的并行处理能力,在服务器应用性能上的拖累,无法满足Parallel Scavenge 收集器吞吐量最大化!
在这里插入图片描述
所以Parallel Old 收集器的出现就是为了配合Parallel Scavenge 收集器,使得吞吐量最大化,也是名副其实的吞吐量优先组合

CMS 收集器

CMS 收集器是一款以获取最短回收停顿时间为目标的收集器,它是基于标记-清除算法实现的,它的运作过程很复杂,分为4步,下面具体的说一下每一步

  • 初始标记
    初始标记仍然需要Stop The World ,它仅仅是标记一下GC Roots能直接关联的对象,速度很快
  • 并发标记
    从GC Roots对象 开始遍历整个对象图,这个过程用时很长,但是和用户线程一起并发执行,就是不需要用户等待
  • 重新标记
    重新标记也需要Stop The World,修正在上一步并发标记的过程中,因为用户程序的运行导致一部分对象的引用发生了变化,这个阶段的时间也很短,
  • 并发清理
    清理掉已经标记死亡的对象,这个过程也不需要用户等待,与用户线程并发执行

优点

  • 并发收集,低停顿

缺点

  • CMS收集器是并发的,所以它会占用一部分线程,导致应用程序变慢
  • 无法处理浮动垃圾
    至于 “浮动垃圾”,因为 CMS 在 并发标记 时是并发的,GC 线程和用户线程并发执行,这个过程当然可能会因为线程的交替执行而导致新产生的垃圾(即浮动垃圾)没有被标记到;而 重新标记 的作用只是修改之前 并发标记 所获得的不可达对象,所以是没有办法处理 “浮动垃圾” 的。
  • 它是基于标记–清除算法的,肯定会产生内存碎片

总结

篇幅有点长了后面的文章还会更新G1收集器、Shenandoah收集器、ZGC收集器等优秀的垃圾收集器
上面的几种垃圾收集器,你学废了吗?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章