前面简单介绍了如何确定对象是垃圾、什么时候回收、怎么回收,今天就来聊一聊java中常见的垃圾回收器,从Serial到G1,其中会着重解读CMS和G1的工作原理,包括如何安全的并发回收、cSet、rSet等以及他们各自的优缺点;下面按照新生代、老年代进行分类介绍

新生代垃圾回收器

一、Serial收集器(STW)

  Serial收集器是一个单线程的、采用标记-复制算法的、回收时需要暂停用户线程(STW)的新生代垃圾回收器;可与serial old或cms搭配使用;但JDK9后已不再支持Serial与CMS的组合

二、ParNew收集器(STW)

  ParNew是Serial的多线程版,即垃圾回收线程有多个,但是也是需要STW,回收算法采用的也是标记-复制,除了Serial收集器外只有它可与CMS搭配工作;但自JDK9后已不再支持其与SerialOld的组合,加上上文说的也不支持Serial与CMS的组合,所以JDK9后能与CMS搭配的新生代回收器只有ParNew了;

三、Parallel Scavenge(STW)

  与ParNew一致,Parallel Scavenge是基于标记-复制算法的多线程的新生代垃圾回收器,但是其关注的是吞吐量优先;吞吐量高意味着垃圾收集的时间短,而要确保垃圾收集时间短,在回收策略优化调整的基础上也会不可避免的会使垃圾回收的次数增加,而垃圾回收次数增加又会造成用户代码的停顿次数变多,这就要看用户根据实际情况取舍了,一般针对cpu密集型的程序更关注吞吐量,而io密集型的就需要去平衡下吞吐量和用户代码停顿时间的关系了;

  • 吞吐量

    吞吐量=执行用户线程的时间/(执行用户线程的时间+垃圾收集的时间)
  • Parallel Scavenge的常用参数

    -XX:MaxGCPauseMills;指定垃圾收集能停顿的最大时间,单位毫秒,收集器将尽量保证垃圾回收的时间不超过该设定的时间;

    -XX:GCTimeRatio;设置吞吐量大小,取值范围为0-100

    -XX:+UseAdaptiveSizePolicy;开关参数;开启后就不用用户去指定新生代的大小(-Xmn)、Eden与Survivor的比例(-XX:SurvivorRatio)等参数了,虚拟机会根据当前系统的运行情况自动收集性能监控信息,动态调整这些参数以达到最合适的停顿时间或吞吐量,这种调节方式称为垃圾收集的自适应调节;

老年代垃圾回收器

一、Serial Old(STW)

  是Serial收集器的老年代版本,负责回收老年代,同意也是单线程GC,由于回收的是老年代,没有其他的空积做担保,所以采用的是标记-整理算法

二、Parallel Old(STW)

  多线程的基于标记-整理算法的老年代垃圾回收器;是Parallel Scavenge的老年代版本;PS+PO的搭配也是JDK8的默认垃圾收集器的搭配;

三、CMS

  是一款关注用户响应时间的老年代垃圾回收器,其在回收中的某些阶段做到了不用暂停用户线程,这在垃圾收集器的历史上具有里程碑的意义,但是其在触发FULLGC后清理老年代的回收器是Serial,单线程的垃圾回收器,显而易见的慢;另外CMS还是唯一一款会单独回收老年代(Old GC)的垃圾回收器,下面介绍下CMS的回收过程以及优缺点

  • 回收过程

    1、初始标记(STW)

    只标记gcroots可直接关联的对象,时间会很快;

    2、并发标记

    标记那些需要被回收的对象,是与用户线程一起运行的,所以有可能会产生漏标的情况发生,CMS使用的是三色标记算法的增量更新算法来解决这一问题,算法详情可参考上篇文章;

    3、重新标记(STW)

    针对并发标记阶段用户线程产生的新垃圾进行重新标记

    4、并发回收

    开始回收垃圾,因为同样是与用户线程一起运行的,所以用户线程会产生新的垃圾,这些垃圾被称为浮动垃圾,只能下次清理时处理;
  • 优点

    支持垃圾线程和用户线程并发执行,减少了用户的等待时间
  • 缺点

    结合回收过程CMS的缺点也是显而易见的,大致可分为以下三种:

    1、由于最后回收阶段采用的是并发回收,用户线程产生的垃圾是必须要到下次GC才会被回收,会产生浮动垃圾;

    2、并发回收阶段采用的是标记-清除算法,这样容易产生内存碎片,导致内存不规整,有可能分配不下大对象而产生FULLGC,而上面也说过了,FULLGC时CMS采用的是Serial

    3、CMS并发回收阶段使用的线程数是通过(CPU核心数+3)/4计算而来,这样一来,CPU核数大于4还好,如果小于4的话那就意味着最差需要用一半的线程来进行垃圾回收,回影响系统的吞吐量

全堆垃圾收集器

G1

  G1是一款面向全推进行回收的可以与用户线程一起进行的垃圾回收器;其在CMS的基础上做了一定程度的优化,但成本就是堆内需要使用部分内存来供G1本身使用;与上面介绍的一堆垃圾收集器相比,G1只在逻辑上进行了分代,物理上比没有划定哪些区域是新生代或老年代;G1还推出了时间响应模型即在给定的M毫秒时间内用于垃圾回收的时间不超过N毫秒,这一实现主要依赖于collection set(CSet)来实现;下面介绍下G1的回收模型和优缺点

回收模型

minorGC

新生代的初始大小有个默认值,约占堆空间的5%-60%,由G1根据需要动态调整;当达到设置的阈值时进行YGC

MixedGC
  • 定义

    G1与上面介绍的其他收集器不同,不用将新老年代限制死,回收时要么回收新生代(minorGC),要么老年代(majorGC)要么全堆收集(FullGC),G1可以面向堆内存的任何部分来组成回收集(Cset)进行回收;衡量标准不再是垃圾属于哪个分代,而是哪块内存垃圾多回收收益最大,这就是G1的MixGc模式;MixedGC也会有个触发的默认值.超过该值进行GC,默认应该是堆空间的45%
  • 回收过程

    1、初始标记:和CMS的初始标记一样只标记GC Roots能直接关联到的对象,并修改TAMS指针的值,让下一阶段用户线程并发运行时能正确地在可用的region中分配对象;需要暂停用户线程,但耗时很短,且是借用Minor GC的时候同步完成的,所以并没有额外的停顿

    2、并发标记:从GC Root开始对堆中对象进行可达性分析,找出要回收的对象,耗时较长所以可以与用户线程并发执行;扫描完后会维护SATB记录下来的并发时由用户线程造成的引用发生改变的对象(三色标记的SATB算法)

    3、最终标记:暂停用户线程,处理并发标记阶段SATB中维护的引用发生改变的记录

    4、筛选回收:暂停用户线程,对各region的回收价值和回收成本进行排序,根据用户期望的停顿时间来制定回收计划,可以选择任意个region构成回收集,然后把需要回收的region中的存货对象复制到空的region中,再清理掉region的全部空间;由多条GC线程并行完成上述操作
FullGC

当堆空间不足以分配新对象时触发FGC

优点

1、全堆垃圾收集器;

2、仅进行了逻辑上的分代,物理上并不分代;

3、逻辑上保留了新老年代的概念,但新老年代的位置并不固定,它们是一系列区域(不需要连续)的动态集合;

4、Region为G1的最小回收单元;可由-XX:G1HeapRegionSize设定每个region的大小,取值范围为1-32MB,且应为2的N次幂

5、利用停顿时间模型用户可以指定垃圾收集的停顿时间,G1也会尽量满足这个设定的时间

缺点

1、为了垃圾收集而产生的内存占用和程序运行时的额外执行负载都比CMS要高

2、G1每个region中维护的记忆集(Rset)可能会占整个堆容量的20%甚至更多;而CMS使用的是卡表,全堆只需维护一份,且只需记录老年代到新生代的引用;

collections set(cSet)

维护了需要下次垃圾回收的region的集合,并且根据回收价值进行了排序,这样筛选回收时就能根据系统默认或者用户设定的响应时间优先回收价值高的region

remember set(rSet)

每个region维护一个rSet,用来记录别的对象到本region的引用,用rSet就是为了解决垃圾回收时对象跨代引用的扫描问题,这样操作大大节省了GC回收时扫描的时间;但是随之而来的问题是,维护rSet也是需要一定内存空间的;

jvm之垃圾收集二之常用垃圾收集器的更多相关文章

  1. JVM系列(二) — Java垃圾收集介绍

    这篇文章主要从以下几个方面介绍垃圾收集的相关知识 一.判断对象是否已死 二.主流垃圾收集算法 三.内存分配与回收策略 本章节主要从以下几个思考点着手介绍垃圾回收的相关知识:哪些内存需要回收?什么时候回 ...

  2. JVM知识(二):类加载器原理

    我们知道我们编写的java代码,会经过编译器编译成字节码(class文件),再把字节码文件装载到JVM中,最后映射到各个内存区域中,我们的程序就可以在内存中运行了.那么问题来了,这些字节码文件是怎么装 ...

  3. JVM(HotSpot)7种垃圾收集器

    JVM(HotSpot)7种垃圾收集器 7种垃圾收集器作用于不同的分代,如果两个收集器之间存在连续,就说明他们可以搭配使用. 从JDK1.3到现在,从Serial收集器->Parallel收集器 ...

  4. 【Java】JVM(三)、Java垃圾收集器

    一.Minor GC.Major GC 和 Full GC Minor GC:清理新生代空间,当Eden空间不能分配时候引发Minor GC Major GC:清理老年代空间 Full GC:清理Ja ...

  5. JVM学习笔记-第三章-垃圾收集器与内存分配策略

    JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...

  6. 垃圾收集器之:G1收集器

    G1垃圾收集器是一种工作在堆内不同分区上的并发收集器.分区既可以归属于老年代,也可以归属新生代,同一个代的分区不需要保持连续.为老年代设计分区的初衷是我们发现并发后台线程在回收老年代中没有引用的对象时 ...

  7. [转帖]JVM—深入理解内存模型与垃圾收集机制

    JVM—深入理解内存模型与垃圾收集机制 https://juejin.im/post/5d68dc9ee51d4561ad6548f7 前言 Java是一种跨平台的语言,当初其设计初衷也是为了解决各个 ...

  8. 垃圾收集器之:CMS收集器

    HotSpot JVM的并发标记清理收集器(CMS收集器)的主要目标就是:低应用停顿时间.该目标对于大多数交互式应用很重要,比如web应用.在我们看一下有关JVM的参数之前,让我们简要回顾CMS收集器 ...

  9. JVM体系结构之二:类加载器

    一.概述 定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型.类加载和连接的过程都是在运行期间完成的. 二. 类的加载 ...

随机推荐

  1. spring boot 分布式session实现

    spring boot 分布式session实现 主要是通过包装HttpServletRequest将session相关的方法进行代理. 具体是的实现就是通过SessionRepositoryFilt ...

  2. Math_Music

    查看代码 #REmoo的优化任务 #1.公式写在<formula_set>类中,统一管理 --- Finished 2022.8.15 12:39 #2.建立<sample_set& ...

  3. C语言小游戏:贪吃蛇

    #include <graphics.h> #include <conio.h> #include <stdio.h> #define WIDTH 40 //设置宽 ...

  4. MAC MySQL安装配置

    1. 下载 下载地址:https://dev.mysql.com/downloads/mysql/ 注意选择对应的版本,M系列芯片对应ARM 2. 安装 参考官网教程, 点击地址查看, 一直点击继续即 ...

  5. Kibana仪表盘(Dashboard)详解

    Kibana 仪表板(Dashboard) 展示保存的可视化结果集合. 在编辑模式下,您可以根据需要安排和调整可视化结果集,并保存仪表板,以便重新加载和共享. 创建一个仪表板 如何创建一个仪表板: 点 ...

  6. 从dva到vuex的使用方法()

    官网文档:https://vuex.vuejs.org/zh/ 辅助理解的博客:https://blog.csdn.net/m0_70477767/article/details/125155540 ...

  7. Oracle基础知识汇总一

    Oracle基础知识 以下内容为本人的学习笔记,如需要转载,请声明原文链接   https://www.cnblogs.com/lyh1024/p/16720759.html oracle工具: SQ ...

  8. mac通过docker一键部署Jenkins

    目录 mac通过docker一键部署Jenkins 一.前言 二.系统配置 三.安装步骤 Dockerhub查看镜像地址 1.一键安装 1.1.下载脚本 1.2.安装程序 1.2.1.安装程序详情 1 ...

  9. 云原生强大且灵活的持续集成CI开源框架Tekton实战-上

    @ 目录 概述 定义 常见CICD工具 使用好处 组件 基本概念 安装 前提条件 安装Tekton Pipelines 创建并运行任务 安装Dashboard 安装Cli Pipelines示例演示 ...

  10. aws-cli命令-vpcs及subnets相关的查询

    关于AWS上vpcs及subnets相关的查询,常用的命令如下: # 查询所有的vpc信息 aws ec2 describe-vpcs --output json # 查询所有所有的subnet相关的 ...