性能优化|这应该是总结的最到位的关于垃圾收集器技术要点的文章了

507 阅读5分钟

垃圾收集器是垃圾回收算法的具体实现

Serial收集器(-XX:+UseSerialGC -XX:+UseSerialOldGC)

通过字面意思理解,Serial收集器是一个串型收集器,它以单线程执行垃圾回收工作,也就是说在多核CPU,它还是以单线程进行垃圾回收工作; 在这里插入图片描述

Serial收集器在工作时,会停止所有运行的代码,会出现STW(stop the world),直到收集结束,才恢复代码的运行。

Serial收集器由于单线程运行,不需要额外承担线程切换带来的损耗,从而提高收集效率。

Serial有两个用途,第一个是在jdk1.5及以前搭配Parallel Scavenge使用,另外一个是搭配CMS收集器使用,gc失败,会在老年代中使用Serial收集器收集垃圾。

ParNew收集器(-XX:+UseParNewGC)

ParNew收集器是serial收集器的多线程版本,在收集过程中也会出现STW,默认回收的线程个数是和系统的CPU核数一样的,当然你也可以使用-XX:ParallelGCThreads参数指定回收的线程个数 在这里插入图片描述

Parallel Scavenge收集器(-XX:+UseParallelGC(年轻代),- XX:+UseParallelOldGC(老年代))

Parallel Scavenge 收集器类似于ParNew 收集器,是Server 模式(内存大于2G,2个cpu)下的 默认收集器。

Parallel Scavenge收集器关注的是吞吐量,指的是用户运行代码消耗的时间与CPU总消耗时间的占比,也会出线STW现象。Parallel old 是老年代的收集器。

CMS收集器(-XX:+UseConcMarkSweepGC(old))

CMS收集器是一款真正意义上的并发垃圾收集器,它能够让用户程序和垃圾收集程序同时工作运行。

CMS收集器不同于前面的收集器,他为了实现并发收集,并且为了收集的更加干净,它在收集过程中添加了多个步骤:

  • 初始标记:暂停所有线程,只记录gc root能直接引用的对象,速度非常快;
  • 并发标记:这阶段不停止用户程序,收集器和用户程序同时运行,标记那些可达对象;
  • 重新标记:这个阶段用来标记那些在并发标记阶段那些新产生的可达的引用对象,这阶段会暂停用户线程,造成用户线程短暂停顿
  • 并发清理:这阶段开始GC线程和用户线程同时运行,GC线程开始清理那些未被标记的不可达对象
  • 并发压缩:如果用户开启了-XX:+UseCMSCompactAtFullCollection参数,则会执行碎片化处理;
  • 并发重置:清理结束后,会将那些被标记的对象的标志位清除掉; 在这里插入图片描述

CMS收集器的优缺点:

优点

  • 停顿时间短
  • 收集快(采用并发收集)

缺点

  • 收集之后,会产生碎片(可以使用-XX:+UseCMSCompactAtFullCollection,在清理之后进行压缩)
  • 边收集边运行,造成收集的不干净
  • 在收集过程中,程序在运行,有可能还没收集完成,又触发了一次FULL GC,就会出现“concurrent mode failure”,如果出现这个,CMS收集器将会降级,使用串型收集器(Serial old),进行垃圾收集,此时还是会出现STW。

G1收集器(-XX:+UseG1GC)

g1收集器是面向主要针对大内存及多处理器的服务器而开发出来的一款垃圾收集器,它能够提供低停顿的收集时间的同时又能够带来高吞吐量。

g1垃圾收集器和上面所有的垃圾收集起都不同,它将对空间换分成大小相同的region,JVM最多可以有2048个region,region大小可以通过参数-XX:G1HeapRegionSize指定来;

默认情况下新生代的大小占比堆空间的5%,可以使用参数-XX:G1NewSizePercent进行修改;

与其他垃圾收集器不同的是,g1垃圾收集中多了一个Humongous区,如果一个对象分配的内存大小超过了region区域的50%,就会直接放到Humongous区中,如果对象太大,一个region放不下,可以横跨多个region进行存储,这么做的目的是为了防止短暂存活的大对象被分配到了老年代,导致老年代的空间不够,频繁发生full gc;

g1收集器的回收步骤:

  • 初始标记:暂停所有线程,标记gc root 能够直接引用的对象;
  • 并发标记:和CMS标记相同;
  • 最终标记:同CMS重新标记;
  • 筛选回收:g1会对每个region的回收成本做分析,回收成本指的是,如果要回收这个region中的非存活对象大概需要多长时间;做完成本分析之后,会进行排序,成本低的开始往高处回收,但是不是一次性全部回收,具体一次回收多少是有用户期望的GC停顿时间参数(-XX:MaxGCPauseMillis)设定的,如果用户期望GC停顿时间为200ms,那么jvm在回收之前会计算好,那几个区域加起来的停顿时间加起来刚好在200ms以内,把满足的region进行回收,这样就做到了控制GC的停顿时间。

g1收集器的主要特点:可预测的停顿;

g1收集器的分类

YoungGC

g1收集的young gc和其他收集器 young gc触发的事件是不一样的,eden区满的话并不会触发一次 young gc,g1会计算回收当前所有的eden区的时间是否大于等于-XX:MaxGCPauseMills参数设定的值,如果小于,则会创建新的region作为eden区给新对象存放,否则发生young gc;

MixedGC

这个是在g1中新增加的一个gc类别,它会在老年代的区域占有比例达到参数(-XX:InitiatingHeapOccupancyPercen)设定的值,会触发,它回收的区域为young区域和部分old区域,使用复制算法,将存活对象复制到其它的空的region中,如果没有足够的内存,则会触发full gc

FULL gc

停止所有线程,使用单线程回收所有垃圾,使用标记-清理-压缩;

微信搜一搜【乐哉开讲】关注帅气的我,回复【干货领取】,将会有大量面试资料和架构师必看书籍等你挑选,包括java基础、java并发、微服务、中间件等更多资料等你来取哦。