怎么查看默认的垃圾收集器是哪个?

JVM参数:

java -XX:+PrintCommandLineFlags -version

1610803596192.png

默认的垃圾收集器有哪些?

java的gc回收的类型主要有几种:

  • UseSerialGC
  • UseParallelGC
  • UseConcMarkSweepGC
  • UseParNewGC
  • UseParallelOldGC
  • UseG1GC

其实是有7种,但是UseSerialOldGC不推荐使用,被废弃了,因此变为6种

垃圾收集器(重要)

1610803596260.png

1610803596328.png

部分参数预先说明

  • DefNew :Default New Generation(新生代)
  • Tenured :Old
  • ParNew :Parallel New Generation
  • PSYoungGen :Parallel Scavenge
  • ParOldGen :Parallel Old Generation

Server/Client模式分别是什么意思

使用范围:只需要掌握Server模式即可,Client模式基本不会用。

操作系统:

  • 32位操作系统,不论硬件如何都默认使用Client的JVM模式。
  • 32位操作系统,2G内存同时有2个CPU以上用Server模式,低于该配置还是Client模式。
  • 64为only server模式

新生代

串行GC(Serial)/(Serial Copying)

新生代和老年代都是只有一条线程

串行收集器:Serial收集器

一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有的工作线程知道它收集结束。

1610803596357.png

对应JVM参数是:

-XX:+UseSerialGC

开启后会使用:Serial(Young区用)+Serial Old(Old区用)的收集器组合。

表示:新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记-整理算法。

  1. -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m -XX:+PrintCommandLineFlags -XX:+UseSerialGC

代码

  1. /**
  2. * Created by gysui on 2020/12/7
  3. */
  4. public class GCOverheadLimit {
  5. public static void main(String[] args) {
  6. int i = 0;
  7. List<String> list = new ArrayList<>();
  8. try {
  9. while (true) {
  10. list.add(String.valueOf(++i));
  11. }
  12. } catch (Exception e) {
  13. System.out.println("---------------- i = " + i);
  14. e.printStackTrace();
  15. }
  16. }
  17. }

自己运行查看结果

并行GC(ParNew)

新生代多个并行清理垃圾,老年代还是一个

  1. -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParNewGC

ParNew(并行)收集器

一句话:使用多线程进行垃圾回收,在垃圾收集时,会Stop-the-World暂停其他所有的工作线程直到它收集结束。

1610803596391.png

ParNew收集器其实就是Serial收集器新生代的并行多线程版本,最常见的应用场景是配合老年代的CMS GC工作,其余的行为和Serial收集器完全一样,ParNew垃圾收集器在垃圾收集过程中同样也要暂停所有其他的工作线程。它是很多java虚拟机运行在Server模式下新生代的默认垃圾收集器。

常用对应JVM参数:

-XX:+UseParNewGC 启用ParNew收集器,只影响新生代的收集,不影响老年代。

开启上述参数后,会使用:ParNew(Young区用)+Serial Old的收集器组合,新生代使用复制算法,老年代采用标记-整理算法。

但是, ParNew+Tenured这样的搭配,java8已经不再推荐

Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release

备注

-XX:ParallelGCThreads 限制线程数量,默认开启和cpu数目相同的线程数

并行回收GC(Parallel)/(Parallel Scavenge)

-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParallelGC

Parallel Scavenge收集器类似ParNew也是一个新生代垃圾收集器,使用复制算法,也是一个并行的多线程的垃圾收集器,俗称吞吐量有限收集器。一句话:串行收集器在新生代和老年代的并行化。

它重点关注的是:可控制的吞吐量
  (Thoughput=运行用户代码时间/(运行用户代码时间+垃圾收集时间),也即比如程序运行100分钟,垃圾收集时间1分钟,吞吐量就是99%)。高吞吐量意味着高效利用CPU的时间,它多用于在后台运算而不需要太多交互的任务。

自适应调节策略也是ParallelScavenge收集器与ParNew收集器的一个重要区别。(自使用调节策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间(-XX:MaxGCPauseMillis)或最大的吞吐量。)

常用JVM参数:

  • -XX:+UseParallelGC或-XX:+UseParallelOldGC(可互相激活
  • 使用Parallel Scanvenge收集器

新生代和老年代都是多个一起清理垃圾

测试代码

  1. /**
  2. * Created by gysui on 2020/12/7
  3. */
  4. public class GCOverheadLimit {
  5. public static void main(String[] args) {
  6. int i = 0;
  7. List<String> list = new ArrayList<>();
  8. try {
  9. while (true) {
  10. list.add(String.valueOf(++i));
  11. }
  12. } catch (Exception e) {
  13. System.out.println("---------------- i = " + i);
  14. e.printStackTrace();
  15. }
  16. }
  17. }

配置jvm阐述运行

老年代

串行GC(Serial Old)/(Serial MSC)

串行收集器:Serial收集器
一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有的工作线程知道它收集结束。

1610803596418.png

对应JVM参数是:
-XX:+UseSerialGC

开启后会使用:Serial(Young区用)+Serial Old(Old区用)的收集器组合。
表示:新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记-整理算法。

  1. -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC

新生代和老年代都是只有一条线程

并行GC(Parallel Old)/(Parallel MSC)

Parallel Old收集器是Parallel Scavenge的老年代版本,使用多线程的标记-整理算法,Parallel Old收集器在JDK1.6才开始提供。

在JDK1.6之前,新生代使用Parallel Scavenge收集器只能搭配年老代的Serial Old收集器,只能保证新生代的吞吐量优先,无法保证整体的吞吐量。在JDK1.6之前(Parallel Scavenge + Serial Old)

Parallel Old 正是为了在老年代同样提供吞吐量优先的垃圾收集器,如果系统对吞吐量要求比较高,JDK1.8后可以优先考虑新生代Parallel Scavenge和年老代Parallel Old收集器的搭配策略。在JDK1.8及以后(Parallel Scavenge + Parallel Old)

JVM常用参数:
-XX:+UseParallelOldGC 使用Parallel Old收集器,设置该参数后,新生代Parallel+老年代Parallel Old

-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParallelOldGC

并发标记清除GC(CMS)

CMS收集器(Concurrent Mark Sweep:并发标记清除)是一种以获取最短回收停顿时间为目标的收集器。

适合应用在互联网站或者B/S系统的服务器上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短。

CMS非常适合堆内存大、CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器。

1610803596458.png

Concurrent Mark Sweep并发标记清除,并发收集低停顿,并发指的是与用户线程一起执行。

开启该收集器的JVM参数:-XX:+UseConcMarkSweepGC 开启该参数后会自动将-XX:+UseParNewGC打开

开启该参数后,使用ParNew(Young区用)+CMS(Old区用)+Serial Old的收集器组合,Serial Old将作为CMS出错的后备收集器。

4步骤

  • 初始标记(CMS initial mark)
    只是标记一下GC Roots能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。
  • 并发标记(CMS concurrent mark)和用户线程一起
    进行GC Roots跟踪的过程,和用户线程一起工作,不需要暂停工作线程。主要标记过程,标记全部对象。
  • 重新标记(CMS remark)
    为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。
    由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正。
  • 并发清除(CMS concurrent sweep)和用户线程一起
    清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程。基于标记结果,直接清理对象。
    由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看CMS收集器的内存回收和用户线程是一起并发执行。

优缺点

  • 优点

并发收集低停顿

  • 缺点

并发执行,对CPU资源压力大

由于并发进行,CMS在收集与应用线程会同时增加对堆内存的占用,也就是说,CMS必须要在老年代堆内存用尽之前完成垃圾回收,否则CMS回收失败时,将触发担保机制,串行老年代收集器会以STW的方式进行一次GC,从而造成较大停顿时间。

采用的标记清除算法会导致大量碎片

标记清除算法无法整理空间碎片,老年代空间会随着应用时长被逐步耗尽,最后将不得不通过担保机制对堆内存进行压缩。CMS也提供了参数-XX:CMSFullGCsBeForeCompaction(默认0,即每次都进行内存整理)来指定多少次CMS收集之后,进行一次压缩的Full GC。

测试JVM参数

JVM参数

  1. -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseConcMarkSweepGC

垃圾收集器总结

  1. /**
  2. * 1
  3. * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC
  4. *
  5. * 2
  6. * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParNewGC
  7. *
  8. * 3
  9. * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParallelGC
  10. */
  11. public class GCDemo {
  12. public static void main(String[] args) {
  13. System.out.println("*************GCDemo hello");
  14. try {
  15. String str = "Hello World";
  16. while(true) {
  17. str += str + new Random().nextInt(10000);
  18. str.intern();
  19. }
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

GC之如何选择垃圾收集器

1610803596503.png

1610803596582.png