天天看点

垃圾回收器以及分类1.垃圾回收器的各种组合:2.serial收集器3.seria-old收集器4.ParNew收集器5.Parallel scavenge收集器6.Parallel Old收集器7.CMS收集器(ConcurrentMarkSweep)8.G1收集器

1.垃圾回收器的各种组合:

因为java虚拟机规范对垃圾回收器的实现没有具体的规范,所以不同的厂商实现了不同的回收器。下面一张图是各种不同的垃圾回收器以及可以实现的组合。

垃圾回收器以及分类1.垃圾回收器的各种组合:2.serial收集器3.seria-old收集器4.ParNew收集器5.Parallel scavenge收集器6.Parallel Old收集器7.CMS收集器(ConcurrentMarkSweep)8.G1收集器

有连线的代表两个垃圾回收器可以在年轻代和老年代互相组合。

2.serial收集器

从名字看出这是一个单线程收集器。他是JDK1.3之前新生代的回收器的唯一选择。它代表这是一个单线程的的垃圾回收器。在单线程的情况下,这个垃圾回收期的效果很好,因为单线程没有线程的切换的开销。但是在现在大部分都是多CPU的服务器,所以它现在被使用的很少了。但是他还是JVM运行在Client模式下的默认垃圾收集器。因为一般桌面应用下新生代空间不是很大,使用这个垃圾回收器也可以保证回收的时间在100毫秒左右。

3.seria-old收集器

这个收集器就是serial收集器的老年版本,他同样还是单线程的垃圾回收器。它存在的主要意义的还是JVM运行在client模式下的默认老年代回收器跟serial收集器一起使用,同样它还作为CMS垃圾回收器的后备垃圾回收器。

4.ParNew收集器

ParNew垃圾收集器就是serial回收器的多线程版本。事实上他有很多的代码都是和serial收集器公用的,他是有一个很重要的作用就是作为新生代的垃圾回收器跟CMS垃圾回收器进行组合。但是在单核CPU的情况下,他的效率是没有serial垃圾回收器的效果好的。可以通过-XX:UseConcMarkSweepGC或者-XX:UseParNewGC来指定使用它。默认情况它用于回收垃圾的线程的数目跟CPU的数目相同。可以通过-XX:parallelGCThreads来指定使用的垃圾回收的线程的数目。

5.Parallel scavenge收集器

这个垃圾回收器同样是新生代的垃圾回收器,也是基于复制算法实现的。于ParNew线程一样同样为多线程的垃圾回收器。但是这个垃圾回收器和其他回收器的关注点不同。其他的垃圾回收器是尽可能缩短垃圾回收时对用户线程的缩短时间。但是这个垃圾回收器关注的是一个吞吐量的概念。吞吐量指的是运行用户代码的时间/(运行用户代码时间+垃圾回收时间)。

缩短用户停顿时间对那些高交互性比如一些web项目看中的。而吞吐量是一些运行在后台的计算任务是看重的。

有三个参数可以对这个垃圾回收器进行设置:

-XX:MaxGCPauseMills 这个参数设置单次垃圾回收暂停用户线程的最大时间。注意这个参数不能设置的太小,因为这个设置的太小就会频繁发生GC,导致程序的吞吐量出现下降。

-XX:GCTimeRatio 这个设置的就是程序的吞吐量。假设你设计的是99,那么就是垃圾回收的时间占用程序运行的总时间的1%。

-XX:UseAdaptiveSizePolicy 开启这个参数之后,用户就不需要自己再去设置新生代的大小 -Xmn、Eden区和Survivor区的比例-XX:SurvivorRatio,以及晋升到老年代的年龄-XX:MaxTenuringThreshold的等信息。这些值垃圾回收器会根据策略来自动对这些值进行赋值。这个也是parallel scavenge垃圾收集器一个很大的特点。

6.Parallel Old收集器

这个回收器是Parallel scavenge的老年代版本,他经常和Parallel scavenge一起使用在对内存比较敏感和对吞吐量比较高的场合下使用。

7.CMS收集器(ConcurrentMarkSweep)

CMS收集器也是以追求最小停顿时间为目标的,他相比其他的垃圾收集器有则更为复杂的运作过程。主要分为四步

1.初始标记 只是标记根节点直接关联的引用 需要暂停用户线程

2.并发标记 可以跟用户线程并发执行

3.重新标记 需要暂停用户线程,对并发标记期间新增加的引用关系变化再次标记

4.并发清除 跟用户线程并发进行

CMS收集器已经在很大程度上减少了用户线程的停顿时间,但是他也存在下面三个主要的缺点

1.跟用户线程竞争资源

CMS默认的并发线程数目为(CPU数目+3)/4,当CPU线程大于4的时候,CMS垃圾收集器至少要占用25%的资源。当小于4的时候占用CPU资源更加明显。

2.无法清除浮动垃圾

当收集器在进行并发清除垃圾的时候,由于用户线程还在执行,所以收集器一定不能在老年代已经占用100%的情况下再进行垃圾收集,他要预留一定的空间给用户线程进行使用。这个值可以使用-XX:CMSInitiatingOccupancyFraction来指定。JDK1.6之后这个值默认为92。就是在老年代的空间已经占用90%的时候就会触发一次垃圾回收。这个值如果设置的太高就会出现并发清理的时候用户线程并发执行没有足够的空间分配对象而造成内存分配失败的情况发生。如果发生失败,那么就会转换为serialOld收集器进行回收,从而导致用户线程的停顿时间变长,所以这个值设置的合理很重要。

3.内存碎片

因为这个垃圾回收器是使用的标记-清除算法,所以会产生大量的内存碎片。

有两个值可以进行控制:

-XX:UseCMSCompactAtFullCollection 来指定当没有足够的空间分配对象的时候就进行一次整理,这个是默认开启的。

-XX:CMSFullGCsBeforeCompaction 来指定多少次不整理之后进行一次整理。

8.G1收集器

//TODO