jvm之垃圾收集二之常用垃圾收集器
前面简单介绍了如何确定对象是垃圾、什么时候回收、怎么回收,今天就来聊一聊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之垃圾收集二之常用垃圾收集器的更多相关文章
- JVM系列(二) — Java垃圾收集介绍
这篇文章主要从以下几个方面介绍垃圾收集的相关知识 一.判断对象是否已死 二.主流垃圾收集算法 三.内存分配与回收策略 本章节主要从以下几个思考点着手介绍垃圾回收的相关知识:哪些内存需要回收?什么时候回 ...
- JVM知识(二):类加载器原理
我们知道我们编写的java代码,会经过编译器编译成字节码(class文件),再把字节码文件装载到JVM中,最后映射到各个内存区域中,我们的程序就可以在内存中运行了.那么问题来了,这些字节码文件是怎么装 ...
- JVM(HotSpot)7种垃圾收集器
JVM(HotSpot)7种垃圾收集器 7种垃圾收集器作用于不同的分代,如果两个收集器之间存在连续,就说明他们可以搭配使用. 从JDK1.3到现在,从Serial收集器->Parallel收集器 ...
- 【Java】JVM(三)、Java垃圾收集器
一.Minor GC.Major GC 和 Full GC Minor GC:清理新生代空间,当Eden空间不能分配时候引发Minor GC Major GC:清理老年代空间 Full GC:清理Ja ...
- JVM学习笔记-第三章-垃圾收集器与内存分配策略
JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...
- 垃圾收集器之:G1收集器
G1垃圾收集器是一种工作在堆内不同分区上的并发收集器.分区既可以归属于老年代,也可以归属新生代,同一个代的分区不需要保持连续.为老年代设计分区的初衷是我们发现并发后台线程在回收老年代中没有引用的对象时 ...
- [转帖]JVM—深入理解内存模型与垃圾收集机制
JVM—深入理解内存模型与垃圾收集机制 https://juejin.im/post/5d68dc9ee51d4561ad6548f7 前言 Java是一种跨平台的语言,当初其设计初衷也是为了解决各个 ...
- 垃圾收集器之:CMS收集器
HotSpot JVM的并发标记清理收集器(CMS收集器)的主要目标就是:低应用停顿时间.该目标对于大多数交互式应用很重要,比如web应用.在我们看一下有关JVM的参数之前,让我们简要回顾CMS收集器 ...
- JVM体系结构之二:类加载器
一.概述 定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型.类加载和连接的过程都是在运行期间完成的. 二. 类的加载 ...
随机推荐
- RabbitMQ实现订单超时案例
前言 人间清醒 目录 前言 业务场景 JUC(DelayQueue)方案 DelayQueue简介 JUC DelayQueue实现订单超时案例代码 案例代码 Redis Key过期事件方案 简介 R ...
- Linux虚拟机报错grub rescue解决步骤
/boot 分区内核文件丢失 实验准备 1) 准备:rm -rf /boot/* 2) 系统启动报错截图 修复步骤 重启显示logo时 按 Esc,选择从光驱启动 或者关机再选择打开电源时进入固件 移 ...
- 教大家怎么看monaco-editor的官方文档
最近业务中有用到浏览器在线编辑器,用的是monaco-editor,官网文档只在首页介绍了npm安装方式. 但其实还有另外一种<script>的引入方式,但是这种方式体现在API文档中,由 ...
- 如何使用Postman调试HMS Core推送接口?
HMS Core推送服务支持开发者使用HTTPS协议接入Push服务端.Postman是一款接口测试工具,它可以模拟用户发起的各类HTTP请求,将请求数据发送至服务端,获取对应的响应结果.Postma ...
- Kingbase V8R6存储过程变量数据导出到操作系统文件
Kingbase V8R6存储过程变量数据导出到操作系统文件 说明: KingbaseES V8R6如何将自定义过程中的变量数据导出到操作系统文件中. 本次案例数据库版本: test=# select ...
- QT的字符编码
QString编码:UTF-16 QString内部保存的数据就是QChar数组,是Unicode编码(utf16),在字符显示,操作的时候都是基于Unicode. QString构造时默认采用Lat ...
- VLDB'22 HiEngine极致RTO论文解读
摘要:<Index Checkpoints for Instant Recovery in In-Memory Database Systems>是由华为云数据库创新Lab一作发表在数据库 ...
- VSCODE 配置远程调试环境
以下内容为本人的著作,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16691460.html 我的需求是,在Windows桌面 ...
- Reactor And Gev 详解 通俗易懂
reactor 详解 在类似网关这种海量连接, 很高的并发的场景, 比如有 10W+ 连接, go 开始变得吃力. 因为频繁的 goroutine 调度和 gc 导致程序性能很差. 这个时候我们可以考 ...
- 【微服务】- 配置中心 - Nacos
微服务 - 配置中心 - Nacos 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 今天的学习任务就是学习使用Nacos作为配置中心. 努力克制自己,拒绝摆烂! 什么是配 ...