Java虚拟机9:垃圾收集(GC)-4(垃圾收集器)

1.前言

垃圾收集器是前一章垃圾收集算法理论知识的具体实现了,不同虚拟机所提供的垃圾收集器可能会有很大差别,另外我们必须提前说明一个道理:没有最好的垃圾收集器,更加没有万能的收集器,只能选择对具体应用最合适的收集器。这也是HotSpot为什么要实现这么多收集器的原因,下面我们以HotSpot为例讲解。在写之前,先介绍几个概念。

1.1.并行和并发的区别

这个区别之前在你专门的一节介绍过,这里再重点提一下:这两个名词都是并发编程中的概念,在谈论垃圾收集器的上下文语境中,可以这么理解这两个名词:

1、并行Parallel

多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。

2、并发Concurrent

指用户线程与垃圾收集线程同时执行(但并不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。

1.2.Minor GC和Full GC的区别

  • 新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性(存活率不高),所以Minor GC非常频繁,一般回收速度也比较快。
  • 老年代GC(Major GC / Full GC):指发生在老年代的垃圾收集动作,出现了Major GC,经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。

1.3.吞吐量

吞吐量:就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)。虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。

2.垃圾收集器组合

下面一张图是HotSpot虚拟机包含的所有收集器:

(A):图中展示了7种不同分代的收集器:

Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1;

(B):而它们所处区域,则表明其是属于新生代收集器还是老年代收集器:

      新生代收集器:Serial、ParNew、Parallel Scavenge;

      老年代收集器:Serial Old、Parallel Old、CMS;

      整堆收集器:G1;

(C):两个收集器间有连线,表明它们可以搭配使用

Serial/Serial Old、Serial/CMS、ParNew/Serial Old、ParNew/CMS、Parallel Scavenge/Serial Old、Parallel Scavenge/Parallel Old、G1;

(D):其中Serial Old作为CMS出现"Concurrent Mode Failure"失败的后备预案(后面介绍);

2.1 Serial收集器

  1. 特性:
    最基本、发展历史最久的收集器,采用复制算法的单线程收集器单线程一方面意味着它只会使用一个CPU或一条线程去完成垃圾收集工作,另一方面也意味着在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束为止,这个过程也称为 Stop The world。后者意味着,在用户不可见的情况下要把用户正常工作的线程全部停掉,这显然对很多应用是难以接受的。
  2. 应用场景:
    Serial收集器依然是虚拟机运行在Client模式下的默认新生代收集器。 在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的
  3. 优势:
    简单而高效(与其他收集器的单线程相比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。比如在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的。

Stop TheWorld 说明:

GC在后台自动发起和自动完成的,在用户不可见的情况下,把用户正常的工作线程全部停掉,即GC停顿,会带给用户不良的体验;

从JDK1.3到现在,从Serial收集器-》Parallel收集器-》CMS-》G1,用户线程停顿时间不断缩短,但仍然无法完全消除;

设置参数

      "-XX:+UseSerialGC":添加该参数来显式的使用串行垃圾收集器;

 Serial/Serial Old组合收集器运行示意图如下:

2.2 ParNew收集器

  1. 特性:

    ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集外,其余行为和Serial收集器完全一样,包括Serial收集器可用的所有控制参数、收集算法、Stop The world、对象分配规则、回收策略等都一样。在实现上也共用了相当多的代码。

  2. 应用场景:
    ParNew收集器是许多运行在Server模式下的虚拟机中首选的新生代收集器。很重要的原因是:除了Serial收集器之外,目前只有它能与CMS收集器配合工作(看图)。在JDK1.5时期,HotSpot推出了一款几乎可以认为具有划时代意义的垃圾收集器-----CMS收集器,这款收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程同时工作
  3. 优势:
    在单CPU中的环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销,甚至由于线程交互的开销,该收集器在两个CPU的环境中都不能百分百保证可以超越Serial收集器。当然,随着可用CPU数量的增加,它对于GC时系统资源的有效利用还是很有好处的,它默认开启的收集线程数与CPU数量相同。

设置参数:

      "-XX:+UseConcMarkSweepGC":指定使用CMS后,会默认使用ParNew作为新生代收集器;

      "-XX:+UseParNewGC":强制指定使用ParNew;

      "-XX:ParallelGCThreads":指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同;

ParNew/Serial Old组合收集器运行示意图如下:

2.3 Parallel Scavenge 收集器

  1. 特性:

    Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,也是并行的多线程收集器。

  2. 对比分析:
    • Parallel Scavenge收集器 VS CMS等收集器:
      Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。
      由于与吞吐量关系密切,Parallel Scavenge收集器也经常称为“吞吐量优先”收集器。
    • Parallel Scavenge收集器 VS ParNew收集器:
      Parallel Scavenge收集器与ParNew收集器的一个重要区别是它具有自适应调节策略。
  3. 应用场景:
    Parallel Scavenge收集器是虚拟机运行在Server模式下的默认垃圾收集器。
    停顿时间短适合需要与用户交互的程序,良好的响应速度能提升用户体验;高吞吐量则可以高效率利用CPU时间,尽快完成运算任务,主要适合在后台运算而不需要太多交互的任务。
    该收集器以高吞吐量为目标,就是减少垃圾收集时间,从而让用户代码获得更长的运行时间。所以适合那些运行在多个CPU上,并且专注于后台计算的应用程序,例如:执行批量处理任务、订单处理,工资支付,科学计算等。

设置参数:

虚拟机提供了-XX:MaxGCPauseMillis和-XX:GCTimeRatio两个参数来精确控制最大垃圾收集停顿时间和吞吐量大小。不过不要以为前者越小越好,GC停顿时间的缩短是以牺牲吞吐量和新生代空间换取的。

     "-XX:+MaxGCPauseMillis":控制最大垃圾收集停顿时间,大于0的毫秒数;这个参数设置的越小,停顿时间可能会缩短,但也会导致吞吐量下降,导致垃圾收集发生得更频繁。

     "-XX:GCTimeRatio":设置垃圾收集时间占总时间的比率,0<n<100的整数,就相当于设置吞吐量的大小。

垃圾收集执行时间占应用程序执行时间的比例的计算方法是:

1 / (1 + n)

例如,选项-XX:GCTimeRatio=19,设置了垃圾收集时间占总时间的5%--1/(1+19);

默认值是1%--1/(1+99),即n=99;

垃圾收集所花费的时间是年轻一代和老年代收集的总时间;

        GC自适应的调节策略

Parallel Scavenge收集器有一个参数-XX:+UseAdaptiveSizePolicy。当这个参数打开之后,就不需要手工指定新生代的大小、Eden与Survivor区的比例、晋升老年代对象年龄等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomics)。如果对于垃圾收集器运作原理不太了解,以至于在优化比较困难的时候,使用Parallel收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个不错的选择

时间: 2024-10-09 10:43:49

Java虚拟机9:垃圾收集(GC)-4(垃圾收集器)的相关文章

Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用2

1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用. findClass protected Class<?> findClass(String name) throws ClassNotFoundException 使用指定的二进制名称查找类.此方法应该被类加载器的实现重写,该实现按照委托模型来加载类.在通过父

Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用

1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用. findClass protected Class<?> findClass(String name) throws ClassNotFoundException 使用指定的二进制名称查找类.此方法应该被类加载器的实现重写,该实现按照委托模型来加载类.在通过父

java虚拟机学习(五)--垃圾收集器总结

JVM--垃圾收集器总结 一.垃圾收集器概览 收集算法是内存回收的方法论,垃圾收集据是内存回收的具体实现.Java虚拟机规范中对垃圾收集器应该如何实现没有规定,不同的厂商.不同版本的虚拟机所提供的垃圾收集器可能会有很大差别,一般都会提供参数供用户根据自己的所用特点和要求组合出各个年代所使用的收集器.下面是基于JDK 1.7 Update 14 之后的HotSpot 虚拟机垃圾收集器.如果两个收集器之间有连线就说明它们可以搭配使用.直到现在还没有最好的收集器,更加设有万能的收集器,只是对具体应用选

java虚拟机常见的几种垃圾收集器简介

新生代收集器        Serial收集器 它是最基本.历史最悠久的收集器,在JDK1.3.1之前是虚拟机新生代收集的唯一选择.它是一个单线程的收集器,到现在为止,它依然是虚拟机运行在Client模式下的默认的新生代收集器.优点:简单高效. 特点:只会使用一个CPU或一条收集线程去完成垃圾收集工作,在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束.它没有线程交互的开销,所以可以获得最高的单线程收集效率.   ParNew收集器 Serial收集器的多线程版本,除了使用多条线程进行

Java虚拟机详解----GC算法和种类

本文主要内容: GC的概念 GC算法  引用计数法(无法解决循环引用的问题,不被java采纳) 根搜索算法 现代虚拟机中的垃圾搜集算法: 标记-清除 复制算法(新生代) 标记-压缩(老年代) 分代收集 可触及性 Stop-The-World 一.GC的概念: GC:Garbage Collection 垃圾收集 1960年 Lisp使用了GC Java中,GC的对象是Java堆和方法区(即永久区) 我们接下来对上面的三句话进行一一的解释: (1)GC:Garbage Collection 垃圾收

【深入理解Java虚拟机 】类的加载器

1. 类加载器的分类 JVM 自带的类加载器 根类加载器( BootStrap ) 拓展类加载器 ( Extension ) 系统 (应用) 加载器 ( System / AppClassLoader) 开发者自己创建的类加载器 java.long.ClassLoader 的子类 public abstract class ClassLoader { // 抽象类,不能实例化吗,需要继承并重写其方法 } 2. 加载时机 类加载器不是在 "首次主动" 使用的时候采取尝试加载一般情况下回提

《深入理解java虚拟机》学习笔记四/垃圾收集器GC学习/一

Grabage Collection      GC GC要完成的三件事情: 哪些内存需要回收? 什么时候回收? 如何回收? 内存运行时区域的各个部分中: 程序计数器.虚拟机栈.本地方法栈这3个区域随线程而生,随线程而灭. 栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈的操作. 每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的,因此, 这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需过多考虑回收的问题. 因为方法结束或者线程结束时,内存自然就跟着回收了. 而ja

深入理解Java虚拟机之读书笔记二 垃圾收集器

1.对象已死? a.引用计数算法:缺点是它很难解决对象之间的相互循环引用的问题,Java语言中没有选用它. b.根搜索算法(GC Roots Tracing):通过一系列的名为"GC Roots"的对象作为起始点,开始向下搜索,走过的路径称为引用链,当一个对象没有任何引用链相连,表面此对象不可达.在Java语言中,可作为GC Roots的对象包括: 虚拟机栈(栈帧中的本地变量表)中的引用的对象. 方法区中的类静态属性引用的对象. 方法区中的常量引用的对象. 本地方法栈中JNI的引用的对

《深入理解JAVA虚拟机》----------第三章 垃圾收集器与内存分配策略,读后感(中)

1.垃圾收集器 1.1 Serial收集器 这个收集器是一个单线程的收集器,它在进行垃圾收集时,必须暂停其他所有的工作线程. 它是虚拟机运行在Client模式下的默认新生代收集器,它简单而高效. 1.2 ParNew收集器 其实就是Serial收集器的多线程版本,目前只有它能与CMS收集器配合工作. 原文地址:https://www.cnblogs.com/technologykai/p/10622586.html

Java虚拟机详解05----垃圾收集器及GC参数

[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4748313.html 联系方式:[email protected] 本文主要内容: 堆的回顾 串行收集器 并行收集器 CMS收集器 零.堆的回顾: 新生代中的98%对象都是“朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块比较大的Eden空间和两块较小的Survivor