hxwhero

垃圾回收器ParNew+CMS

  今天记录一下垃圾回收器ParNew和CMS

1.ParNew垃圾回收器

  ParNew垃圾回收器用于回收新生代的垃圾,使用的垃圾回收算法用的就是上节中说的标记复制算法,将新生代eden区中的存活对象标记出来,然后将存活对象复制到一个survive 1区中,然后将eden区中垃圾对象清理掉,下次再满了之后将存活对象复制到suevive 2区中,然后清理掉垃圾对象。ParNew垃圾回收器优化的地方在于可以多线程并发的进行垃圾回收,ParNew垃圾回收器默认开启的垃圾回收线程是跟机器的CPU是一致的,比如机器是4核CPU,那么此时ParNew的垃圾回收线程就是4个线程,当然,这个线程数量是可以进行手动指定的,可以使用参数-XX:ParallelGCThreads 进行指定,但是建议一般不要随意改动这个参数。那么如何开启ParNew垃圾回收器呢,可以使用“-XX:+UseParNewGC

  由此可以看出,使用ParNew垃圾回收器比原始的serial垃圾回收器的区别在于,serial是单线程的,而ParNew是多线程的,所以一般情况下,ParNew垃圾回收器的性能是更好的。

2.CMS垃圾回收器

  CMS垃圾回收器用于回收老年代的垃圾,之前有讲过新生代对象有以下几种情况会进入到老年代中:

    1.分代年龄达到15的对象会转移到老年代中

    2.新生代minor GC后存活的对象比survive区大,这些对象会转移到老年代中

    3.survive区中部分对象大小已经超过了survive区内存的一半,那么超过这部分对象分代年龄的对象将转移到老年代中

    4.大对象会直接进入到老年代中

   老年代触发full gc的条件是:

    1.老年代可用空间小于历次进入老年代存活对象的平均大小

    2.minor gc后进入老年代的存活对象,老年代空间不够 放不下

  之前有说过老年代使用的垃圾算法是标记整理,将老年代中存活对象标记出来后,然后将这些存活对象紧凑的排列在一起,在将其他垃圾对象回收掉,这个过程是非常慢的,老年代存活对象多,既要标记这么多存活对象,还要将这些对象排列在一起,因此,CMS垃圾回收器在此基础上做出一些改进,来优化老年代的垃圾回收,CMS的垃圾回收算法分为4个阶段:初始标记->并发标记->重新标记->并发清理。开启老年代CMS垃圾回收器可使用参数“-XX:+UseConcMarkSweepGc

  1.初始标记

  初始标记阶段,会停掉系统的所有工作线程,进入“STOP THE WORLD”阶段,所谓的“初始标记”,就是标记出GC ROOT直接引用的对象,如下,初始标记会根据“b”这个类的静态变量代表的GC ROOT 去标记出它直接引用的B对象,这个就是初始标记的过程。这里是不会去管C这种对象的,因为对象C是被B类的“c”实例变量引用的,方法的局部变量和类的静态变量是GC ROOT,而类的实例变量则不是,所以初始标记的速度是很快的,虽然会暂停所有的工作线程,但是速度很快,其实影响不是很大

public class A{
  private static B b = new B();  
}

public class B{
    private C c = new C();
}

  2.并发标记

  并发标记是垃圾回收线程跟系统的工作线程并发工作,不会影响程序的正常运行,在运行期间,可以创建对象,也可能部分对象失去引用变成垃圾对象;这一过程中垃圾回收线程会对已有的对象进行gc root追踪,比如这里的实例对象c,被对象B引用了,而对象B是对象A的静态变量引用,那么此时可以认定对象C是被GC ROOT间接引用的,所以C也是不能被回收的,C在这一步中会被标记为存活对象,所有像C这样根据gc root判断为间接引用的对象在这一步都会被标记为存活对象,所以并发标记的过程是很缓慢的,但是是跟系统工作线程并发执行的,所以是不会对系统运行造成影响的

  3.重新标记

  在并发标记阶段中,一边标记存活对象和垃圾对象,垃圾回收线程工作的时候,系统的其他工作线程还是会生成新的对象以及一些对象会成为垃圾对象,所以这第三步重新标记就是把这些新增和变更的对象重新标记一下,而这重新标记是会stop the world,停止系统程序,然后重新标记第二阶段产生的对象和一些失去引用变成垃圾的对象,这个阶段只是对少量的对象进行标记处理,所以这一步是相当块的,所以影响也不是很大

  4.并发清理

  老年代中存活的对象都已经标记出来,在第四步就可以开始清理掉垃圾对象了,这一步的清理是垃圾回收线程是并发执行的,不会stop the world,清理阶段相对来说是比较耗时,但并发处理不会影响系统运行

  综上,CMS的垃圾回收分为以上4个步骤,在原始的垃圾回收算法上进行了优化处理,可以看出,处理相对耗时的是第2和第4不,但这两不是并发处理的,所以对系统没有影响,而第1、第3步的处理速度是比较块的,因此CMS的垃圾回收算法相比较下对系统影响比较小。

   CMS在做出优化的同时也带来了几个细节问题:

  1.并发回收垃圾会导致CPU资源紧张

  CMS第2步和第4步时垃圾回收线程跟工作线程并发执行,这会导致有限的CPU资源被垃圾回收线程占用一部分,CMS默认启动的垃圾回收线程数量是(CPU核数 + 3)/4,比如一个4核8G的机器,垃圾回收线程就有(4+3)/4 = 1个,会占用一个CPU资源。

  2.Concurrent Mode Failure问题

  在并发清理阶段,由于是并发处理的,这个时候也会有可能有新的对象进入到老年代中,同时还变成了垃圾对象,这个垃圾对象称为“浮动垃圾”,比如在老年代并发清理的时候,新生代进行minor gc,可能一些对象进入到老年代,然后这些对象失去引用,那么这些对象就成为了 浮动垃圾,虽然他们是属于垃圾对象,但是由于在并发清理步骤前是没有被标记的,所以这些对象是不会被回收的,需要等到下一次GC的时候才能对这些对象进行回收处理。所以CMS为了保证在并发清理阶段老年代有足够的内存来存放这些对象,一般会在老年代中预留部分空间,也就是说CMS触发垃圾回收是会在老年代内存占用的空间达到一定的比例时触发,可以通过参数“-XX:CMSInitiatingOccupancyFaction”来设置老年代内存已使用多少比例就触发CMS垃圾回收,这里jdk默认的值是92%,也就是说老年代中对象占用了92%的空间,就会触发CMS垃圾回收。

  那么,如果在CMS垃圾回收期间,可能发生新生代minor GC后进入老年代的对象大于老年代的可用内存的情况,这个时候就会发生Concurrent Mode Failure,CMS一边回收垃圾,一边又有新的对象进来,然后老年代空间不够放新的对象了,这个时候就会使用“Serial Old”垃圾回收器来替代CMS垃圾回收器,就是直接把程序进入 stop the world状态,停止所有工作线程,专心进行垃圾回收处理,重新进行GC ROOT追踪 标记存活对象和垃圾对象,重新进行垃圾清理。清理掉之后再恢复系统。

  3.内存碎片问题

  再并发清理之后老年代会存在有垃圾碎片的问题,也就是CMS采用了“标记-清理”的算法,每次标记出垃圾对象,然后一次性回收到,会导致大量的垃圾碎片,太多的垃圾碎片就会导致频繁的full gc,所以CMS不是仅仅使用“标记-清理”算法,这里CMS还有两个参数来控制清理垃圾之后对老年代进行碎片整理,就是把存活对象挪到一块。第一个是“-XX:+UseCMSCompactAtFullCollection”,这个参数默认是打开的,它的意思就是CMS full gc后需要再次进入“stop the world”,停止掉工作线程,然后进行碎片整理,将存活都对象挪到一块。避免内存碎片。第二个参数是“-XX:CMSFullGCsBeforeCompaction”,这个意思是多少次FULL GC后执行一次碎片整理工作,默认值是0,也就是只要进行FULL GC就会进行碎片整理。

  补充:之前有提到触发老年代垃圾回收有以下三个情况:

  1.如果没有开启空间担保规则参数,老年代可用空间小于新生代所有对象的大小,会进行FULL GC,这个参数一般是开启的。

  2.空间担保规则,历次进入老年代对象的平均大小大于老年代可用空间

  3.新生代minor gc后存活对象大于survive区大小而进入到老年代,而老年代空间不够存放这些对象,也会触发FULL GC。

  4.这里再补充一个老年代触发的条件,CMS垃圾回收器会判断当老年代空间已使用参数“-XX:CMSInitiatingOccupancyFaction”设置的比例后,也会进行FULL GC

3.参数整理

  -XX:+UseParNewGC:开启ParNew垃圾回收器

  -XX:ParallelGCThreads:ParNew垃圾回收器使用的线程数量,默认时机器的核数

  -XX:+UseConcMarkSweepGC:开启CMS垃圾回收器

  -XX:CMSInitiatingOccupancyFaction:老年代使用内存占比老年代内存多少时,触发CMS垃圾回收。默认92%

  -XX:+UseCMSCompactAtFullCollection:CMS full gc后进行碎片整理,将存活对象挪到一起,默认是打开的

  -XX:CMSFullGCsBeforeCompaction:多少次CMS full gc后才执行一次碎片整理,默认是0。表示只要CMS 发生full gc,就进行碎片整理

分类:

技术点:

相关文章:

  • 2021-09-04
  • 2021-10-14
  • 2021-05-02
  • 2021-12-03
  • 2021-12-13
  • 2021-05-19
  • 2021-10-11
猜你喜欢
  • 2021-12-02
  • 2021-11-28
  • 2021-11-18
  • 2021-08-29
  • 2021-07-08
  • 2021-08-09
  • 2021-11-18
相关资源
相似解决方案