垃圾回收器介绍

  • 串行回收器:

串行回收器可以在新生代和老年代使用,根据作用不同的堆空间,分为新生代串行回收器和老年串行回收器。

新生代串行回收器:

特点:1、它仅仅使用单线程进行垃圾回收。

          2、它是独占式的垃圾回收。

在串行收集器进行垃圾回收时,java应用程序中的线程都需要暂停,等待垃圾回收的完成。应用程序停止工作,进行等待,这种现象称之为“stop-the-world”。它将造成非常糟糕的用户体验,在实时性比较高的应用场景下,是很难让人接受的。

        -XX:+UseSerialGC参数可以制定虚拟机使用新生代串行收集器和老年代串行收集器。是虚拟机使用client模式下,默认的垃圾收集器。

老年代串行回收器:

老年代串行收集器使用标记压缩算法,和新生代串行收集器一样,是独占式垃圾回收器。但是老年代由于存储空间大,老年代垃圾回收器会比新生代回收更长时间。

若老年代使用串行收集器,可以跟多种新生代回收器配合使用,同时它是CMS回收器的备用回收器。

      -XX:+UseSerialGC:新生代、老年代均使用串行回收器

      -XX:+UseParNewGC:新生代使用ParNew回收器,老年代使用串行回收器

      -XX:+UseParallelGC:新生代使用ParallelGC回收器,老年代使用串行收集器。

  • 并行回收器

新生代ParNew回收器:

    ParNew回收器工作在新生代,它只是将串行回收器多线程化,ParNew也是独占式回收器,在收集过程中,应用程序会全部暂停。但由于是并行的,在并行能力强的CPU上,它产生的停顿时间要短于串行回收器。但是在单CPU或者并发能力弱的系统中,并行回收器效果很可能要比串行回收器差。

    -XX:+UseParNewGC:新生代使用ParNew回收器,老年代使用串行回收器。

    -XX:+UseConcMarkSweepGC:新生代使用ParNew回收器,老年代使用CMS回收器。

     ParNew回收器工作的线程数量可以使用-XX:ParallelGCThreads参数指定。默认情况下,当CPU数量小于8个时,ParallelGCThreads的值等于CPU数量,当CPU数量大于8个时,ParallelGCThreads的值等于3+(5*CPU数量/8)。

新生代ParallelGC回收器

    新生代ParallelGC回收器也是使用复制算法的收集器,同ParNew回收器一样,是多线程、独占式的收集器。ParallelGC回收器有一个重要特点,他非常关注系统的吞吐量。

    -XX:+UseParallelGC:新生代使用ParallelGC回收器,老年代使用串行收集器。

    -XX:+UseParallelOldGC:新生代使用ParallelGC回收器,老年代使用ParallelGC回收器。

ParallelGC回收器提供了两个重要参数来控制系统的吞吐量:

    -XX:MaxGCPauseMilis:设置最大的垃圾收集停顿时间。他的值是大于0的整数,虚拟机会将停顿时间控制在设置的值内,如果希望停顿时间较小,那么将值设置小一些就可以了。但是这样虚拟机可能会使用一个较小的堆,因为小堆会比大堆用的时间少,但是会增加GC回收的次数,从而降低了吞吐量。

    -XX:GCTimeRatio:设置吞吐量的大小。他的值在0到100之间的整数。默认值是19,以为着1/(1+19),将垃圾回收控制在总时间的5%以内。要是设置99,那么垃圾回收的时间应不超过1%。

    我们可以使用-XX:UseAdaptiveSizePolicy可以打开GC自适应策略,在这个模式下,新生代大小,eden,old和suivivior的比例、晋升老年代的对象年龄等参数会被自动整理,来达到堆大小、吞吐量和停顿时间的平衡点。我们可以制定虚拟机的最大堆,目标吞吐量GCTimeRatio和停顿时间MaxGCPauseMilis,让虚拟机自己完成工作。

老年代ParallerOldGC回收器

    老年代ParallelOldGC是回收器也是多线程并发的收集器。它也是一个关注吞吐量的回收器,它只能和新生代ParallelGC回收器一起使用。也是使用标记压缩算法。

    XX:ParallelGCThreads也可用于设置垃圾回收时的线程数量。那么我们看到新生代ParNew回收器也会使用这个参数,那么岂不是冲突了吗?不会的,因为两个收集器是不可能在一起使用的,所以参数一样的,但是并不会起到冲突。

  • 并发垃圾回收器

老年代CMS垃圾回收器

    与Parallel和ParallelOldGC不同,CMS回收器主要关注于系统的停顿时间。CMS是Concurrent Mark Sweep的缩写,意为并发标记清除,从名称上可以得出,它使用的是标记清除算法,同时它是一个使用多线程并行回收的垃圾收集器。

    垃圾回收器介绍

             STW:停顿时间的缩写,在这个时间段应用程序的所有进程全部暂停。

           我们可以看见,CMS中只有初始标记和重新标记两步需要应用程序暂停,其他步骤都是可以与应用程序一起执行的,所以说CMS不是一个独占式的垃圾回收器。初始标记、并发标记、重新标记都是为了标记出需要回收的垃圾对象,并发清理则在标记完成之后,正是回收垃圾对象。并发重置指在垃圾回收完成后,重新初始化CMS数据结构和数据,为下一次垃圾回收做准备。

            在整个CMS回收过程中,默认情况下,在并发标记之后,会有一个预清理的操作(也可以关闭开关-XX:-CMSPrecleaningEnable,不进行预清理)。预清理是并发的,除了为正式做准备和检查以外,预清理还会尝试控制一次停顿时间。由于重新标记是独占CPU的,如果新生代发生GC的时候,就会立即触发一次重新标记,那么一次停顿时间可能会很长。为了避免这种情况,预处理时,会特意等待一次新生代GC的发生,然后根据历史性能数据预测下一次新生代GC可能发生的时间,然后在当前时间和预测时间的中间时刻,进行重新标记。这样,从最大程度上避免新生代GC和重新标记重合,尽可能减少一次的停顿时间。

CMS主要参数:

            -XX:+UseConcMarkSweepGC:新生代使用ParNew回收器,老年代使用CMS回收器。

            CMS默认启动的并发线程数是(ParallelGCThreads+3)/4。我们需要查看当ParNew回收器时设置的ParallelGCThreads参数。并发线程数量也可以通过-XX:ConGCThreads或者-XX:ParallelCMSThreads参数手工设定。当CPU资源比较紧张时,收到CMS回收线程的影响,应用程序的性能在垃圾回收阶段可能会非常糟糕。

            因为CMS不是独占式回收器,所以在进行垃圾回收时,应用系统还在运行,还会不停的创造垃圾,这些新生的垃圾是不会被清除的。同时,因为没有中断,那么在CMS回收时,应确保剩余的堆空间有足够的内存可用,所以CMS不会在堆空间饱和的时候进行垃圾回收,因为要确保有足够的空间可以支持应用程序。

            这个阀值使用-XX:CMSInitiatingOccupancyFraction来指定,默认是68.当老年代使用率达到68了,就进行CMS垃圾回收。如果在执行垃圾回收的时候,内存不足了,CMS垃圾回收就会失败,就会使用串行收集器进行回收,此时应用程序会完全中断。

              因为CMS使用的是标记清除算法,所以他清理后会产生内存碎片,离散内存碎片无法分配较大的对象,这种情况会*进行再进行一次垃圾回收来获取一块可用的连续内存,但是这对系统性能影响很严重。

               使用-XX:+UseCMSCompactAtFullCollectoin开始可以使CMS在垃圾收集完成后,进行一次脆片整理,内存碎片的整理不是并发进行的。-XX:CMSFullGCsBeforeCompaction参数可以用于设定进行多少次CMS回收后,进行一次内存压缩。

               可以使用CMS来回收perm区,必须要打开-XX:+CMSClassUnloadingEnable开关。条件允许的情况下,系统会使用CMS机制回收Perm区的Class数据。

  • 未来做主的:G1回收器

       G1(Garbage-First)回收器是在JDK1.7中正式使用的全新的垃圾回收器。它的出现是为了取代CMS垃圾回收器。

       从分代上看,G1依然属于分代垃圾回收器,它依旧区分年轻代和老年代,依旧分为新生代和老年代。但是堆的结构来看,它不要求整个eden区、年轻代、老年代都连续,它使用了分区算法,来替代CMS长期替代方案。

           (关于后续部分之后在更新。)

 

 

    

    

 

 

 

 

转载于:https://my.oschina.net/WEguo/blog/1574231