JVM调优之垃圾回收器

1、如何找垃圾

 1.1 refence count(引用计数法)

     对象被引用一次会+1,然后被抛弃之后会-1,直到减为0,则表明该对象可以被回收。

     这种方式,无法解决对象被循环引用的问题。

     如下图,对象A被对象B引用,对象B被对象C引用,对象C又被对象A引用,那他们的引用次数都为1,此时它们都不会被回收。

     JVM调优之垃圾回收器

  1.2 GC Root(根可达算法)

     从根对象往下查找,找不到的对象将会被回收,可以解决循环引用的问题。

2、三大垃圾回收算法

    Mark-Sweep(标记-清除算法)

    Coyping(复制算法)

    Mark-Compact(标记-整理(压缩))

2.1 Mark-Sweep

 缺点: 对象回收后可能会存在不连续的内存空间,俗称内存碎片。

  JVM调优之垃圾回收器

2.2 Coyping

采用复制算法会先把存活的对象先复制到连续的内存空间上,复制完后会把可回收的连续内存空间再统一回收,该过程会浪费内存空间,但是不会产生内存碎片。

JVM调优之垃圾回收器

2.3 Mark-Compact

标记整理算法:把可回收的空间和未使用的空间替换成连续的在使用的空间,完了之后统一把存活的内存空间压缩,该过程不会存在内存碎片也不会浪费内存空间,但是该过程效率偏低,需要回收后再压缩。

JVM调优之垃圾回收器

2、垃圾回收器分类

   ParNew与CMS组合,Serial与Serial Old组合,Parallel Scavenge与Parallel Old组合,现在的JDK一般默认使用的都是Parallel与Parallel Old的组合。随着内存的不断增大,垃圾回收器的算法也不断优化。

年轻代的对象什么时候会进入老年代?根据垃圾回收次数判断该对象经过几次回收后仍热存活,则会进入老年代。大多数的垃圾回收器默认是经过15次回收后,仍然存活的对象会进入老年代,但是CMS垃圾收集器默认是6次,jvm调优参数:-XX MaxTenruingThreshold

JVM调优之垃圾回收器

2.1 Serial与Serial Old

 Serial为单线程垃圾收回器,在垃圾回收时会把工作线程先STW(STOP-THE-WORLD),然后再开启一个垃圾线程去回收垃圾。该垃圾回收器是在内存比较小的机器中适用。

2.2 Parallel Scavenge与Parllel Old

 parallel中文的意思是并行,言外之意,就是使用多线程的方式进行垃圾回收。同样,在垃圾回收时会把工作线程先STW(STOP-THE-WORLD),但是会开启多个垃圾回收线程回收垃圾。开启的线程也不可以太多,如果开启的线程太多会造成频繁的上下文切换,造成cpu资源浪费。而且当处理的垃圾过多时,工作线程会一直处于等待的状态(STW),造成页面上用户访问资源一直停滞转圈的情况。

2.3 CMS

CMS:工作线程和垃圾回收线程同时进行。但是在任何版本的JDK默认的垃圾回收器中不存在CMS垃圾回收器,因为CMS存在一些问题(并发过程会产生一些问题)。

CMS工作原理图如下:

JVM调优之垃圾回收器

第一步:进行初始标记,会先停掉工作线程(即STW),然后去寻找根对象,由于根对象很少,所以STW的时间是极短的,所以这个STW是可以接受的。

第二步:并发标记,会出现漏标的情况。就是垃圾线程刚好把一个对象标记为垃圾之后,工作线程又重新引用了该对象。

第三步:重新标记。为了解决第二步出现漏标的情况,第三步会重新STW,扫描被漏标的对象,重新标记。解决漏标的算法,CMS采用三色标记的算法。

第四步:并发清理所有垃圾。

什么是三色标记算法?如下图:

A对象及其属性完全被标记完了,B被扫描到了,但是B的属性还没被标记,D表示还没被扫描到。

JVM调优之垃圾回收器

三色标记算法存在什么问题?

当垃圾线程1扫描A的时候,属性1被扫描完了,此时工作线程1把属性1指向了D,然后垃圾线程2把A标记为灰色,当垃圾线程1把A的所有属性扫描完之后,垃圾线程1把A再标记为黑色,结果出现了D被漏标的情况,这也是CMS回收器的问题所在。

如何解决三色标记算法漏标问题?

必须在重新标记的阶段,重新扫描所有的对象树。

G1垃圾回收器弥补了CMS的缺陷。

未完待续....