探索G1垃圾回收器
前言
最近王子因为个人原因有些忙碌,导致文章更新比较慢,希望大家理解,之后也会持续和小伙伴们一起共同分享技术干货。
上篇JVM的文章中我们对ParNew和CMS垃圾回收器已经有了一个比较透彻的认识,感兴趣的小伙伴可以去回看一下探索ParNew和CMS垃圾回收器。
今天我们继续探索垃圾回收器G1的原理,让我们开始吧!
G1的内存模型
G1是从jdk7开始出现的,在jdk9中被设为默认垃圾收集器,目标就是彻底替换掉CMS,那么为什么它可以替换掉CMS呢?
首先我们就来看看它的内存模型吧。
其实G1是可以同时回收年轻代和老年代的,他最大的特点就是把jvm堆内存拆分为了多个大小相等的Region,那么还存在年轻代和老年代吗?
答案是肯定的,不同的是新生代可能包含了某些Region,老年代也可能包含了某些Region,如下图:
那么到底有多少Region?每个Region有多大呢?
其实这个默认情况下是自动计算的,假如我们给定整个堆内存大小为4096M,然后使用“-XX:+UseG1GC”指定垃圾回收器为G1,此时会自动用堆内存大小除以2048,因为JVM最多可以有2048个Region,然后Region的大小必须是2的倍数。
堆内存为4096M,就会分配给每个Region 2M的内存空间。我们使用G1默认的计算方式就可以了。
当然也可以通过参数“-XX:G1HeapRegionSize”来指定Region的大小。
那么新生代和老年代的默认比例是多少呢?
我们知道使用ParNew和CMS垃圾回收器时,新生代和老年代的默认比例是1:2,而使用G1后,默认新生代对堆内存的初始占比是5%,这个可以通过“-XX:G1NewSizePercent”来设置初始占比,一般不需要设置。
细心的小伙伴会发现,这里说的占比是初始占比,因为系统运行的时候,JVM其实会不停的给新生代增加更多的Region,但是最多新生代的占比不会超过60%,可以通过“-XX:G1MaxNewSizePercent”来设置。
而一旦发生了垃圾回收,新生代的Region数量还会减少,所以其实新生代和老年代的占比不是一成不变的,而是动态改变的。
新生代还有eden和survivor吗?
答案是肯定的,新生代还是有eden和survivor的,只不过内存占用会随着Region的增多而增大。
G1的停顿时间控制
除了内存的变化,G1还有一个最大的变化,就是可以让我们设置一个垃圾回收的预期停顿时间,也就是说我们可以指定G1垃圾回收导致“Stop the World”的最长时间。
我们知道JVM一大痛点就是"Stop the World",尽量减少它的时间就可以做到JVM的优化。
引入G1后,我们可以自己去设定这个停顿的最长时间了,相当于直接控制了垃圾回收的性能。
G1要做到这一点就要去追踪每个Region的回收价值,那什么是回收价值呢?大家看下图:
比如两个Region中,其中一个有10M的垃圾对象,垃圾回收需要耗时1s,另一个有20M的垃圾对象,垃圾回收耗时200ms。
然后G1进行垃圾回收的时候,发现最近1小时垃圾回收已经导致了几百毫秒的系统停顿了,所以会选择回收价值高的Region进行回收,200ms的时间就能回收掉20M的垃圾对象,回收价值相对较高,所以会选择这个Region进行回收
G1控制停顿时间的思路,简单来讲就是,它会通过跟踪Region的回收价值,尽可能的保证系统停顿时间在你设定的停顿时间范围内。
G1的垃圾回收详解
上文我们了解到新生代还是有eden和survivor的,那么随着新生代占据堆内存大小的60%的时候,这个时候就会触发新生代的GC,G1也会使用之前我们说过的复制算法进行垃圾回收,进入一个“Stop the World”状态。
但是这个过程与之前的Minor GC其实是有差别的,首先回收的对象变成了带有垃圾对象的Region,然后回收的同时会根据设定的停顿时间进行价值回收,如上文所述。
那么什么时候进入老年代呢?
这个可以说和之前是一模一样的,简单介绍如下:
新生代躲过多次垃圾回收后会进入老年代;
GC后存活对象超过Survivor区的50%,那么会触发动态年龄判定规则,符合规则的进入老年代。
具体细节不在说明,可以参考王子之前的文章秒懂JVM的垃圾回收机制,有详细解释。
需要注意的是,G1的大对象不是存到老年代中的,而是提供了专门的Region来存放大对象。
在G1中,大对象的判断规则就是这个对象超过了一个Region大小的50%,比如Region是2M的,那如果你的对象超过了1M,就会被认定为大对象,做特殊处理。
而且如果这个大对象过大,可以横跨多个Region进行存储,如下图:
那么老年代具体又是怎么进行垃圾回收的呢?
这个过程说起来可能稍微复杂了一点,但是它和CMS的垃圾回收过程其实是类似的。关于CMS的垃圾回收的几个阶段可以回顾王子的上篇文章探索ParNew和CMS垃圾回收器。
首先我们要弄明白,什么时候会触发新生代和老年代的混合垃圾回收?
G1有一个参数“-XX:InitiatingHeapOccupancyPercent”,默认值为45%。
什么意思呢?就是说当老年代占据了堆内存的45%的Regionf的时候,就会触发混合垃圾回收。
那具体流程是什么样的呢?
首先会触发一次初始标记操作,这个过程是要“Stop the World”的,对应的就是CMS的初始标记阶段,细节不再说明。
接着会进入并发标记阶段,这个阶段同样对应CMS的并发标记阶段,不再说明。
接着会进入最终标记阶段,这个阶段其实和CMS的重新标记阶段也基本一致。
最后就是混合回收阶段,这个阶段和CMS的并发清理阶段就不太一样了,这个阶段会计算每个Region中的存活对象数量,存活数量占比,还有执行垃圾回收的耗时等问题。
接着会进入“Stop the World”阶段,然后全力以赴进行垃圾回收,并尽量保证停止时间不超过我们设定好的时间,所以可能只会回收掉之前标记好的一部分垃圾对象。
为什么要叫做混合回收呢,因为它不仅仅回收的是老年代,新生代和大对象的Region也会同时进行回收,而具体回收哪些Region就要视情况而定了,根据价值回收价值G1会自己做出选择。
而混合回收是可以进行多次的,比如先停止系统,混合回收掉一部分Region,再停止系统,再执行一次混合回收。
有参数可以控制这个数量,“-XX:G1MixedGCCountTarget”参数,就是在一次混合回收的过程中,最后一个阶段执行几次,默认是8次。
那么为什么要这样反复多次的回收呢?
因为这样每次回收停止系统的时间都很短,在回收的间隙系统是可以正常运行的。
还有个参数“-XX:G1HeapWastePercent”,默认值是5%。
它的意思是,混合回收的时候,都是基于复制算法进行的,把Region存活的对象放入其他Region,然后清除掉本来的Region。那么当空闲的Region数量达到堆内存的5%,就会立即停止混合回收。
而通过这种复制算法回收,也不会出现像CMS标记清理算法导致的内存碎片问题。
还有个参数“-XX:G1MixedGCLiveThresholdPercent”,默认值是85%,意思就是回收Region的时候,存活的对象必须少于85%才可以被回收掉。否则存活对象太多,复制的时候成本是很高的。
那么如果回收失败怎么办?
如果在复制的时候发现没有空闲的Region可以承载存活的对象,那么会触发失败,立马停止系统进程,采用单线程进行标记、清理和压缩整理,空闲出一批Region,这个过程是极慢的。
总结
本文我们对G1的内存机制和垃圾回收的算法做了一个比较清晰的解释。
阅读完本文,相信小伙伴们自己可以总结出G1和CMS究竟有什么不一样了吧。
欢迎小伙伴们留言区讨论G1和CMS的区别,王子会第一时间回复。
那我们下篇文章再见。
往期文章推荐:
探索G1垃圾回收器的更多相关文章
- G1垃圾回收器
垃圾回收器的发展历程 背景 01.G1解决的问题 G1垃圾回收器是04年正式提出,12开始正式支持,在17年作为JDK9默认的垃圾处理器. 在04年的时候,java程序堆的内存越来越大,从而导致程序中 ...
- 深入浅出具有划时代意义的G1垃圾回收器
G1诞生的背景 Garbage First(简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式.HotSpot开发团队最初 ...
- JVM学习——G1垃圾回收器(学习过程)
JVM学习--G1垃圾回收器 把这个跨时代的垃圾回收器的笔记独立出来. 新生代:适用复制算法 老年代:适用标记清除.标记整理算法 二娃本来看G1的时候觉得比较枯燥,但是后来总结完之后告诉我说,一定要慢 ...
- G1垃圾回收器在并发场景调优
一.序言 目前企业级主流使用的Java版本是8,垃圾回收器支持手动修改为G1,G1垃圾回收器是Java 11的默认设置,因此G1垃圾回收器可以用很长时间,现阶段垃圾回收器优化意味着针对G1垃圾回收器优 ...
- G1 垃圾回收器简单调优
G1: Garbage First 低延迟.服务侧分代垃圾回收器. 详细介绍参见:JVM之G1收集器,这里不再赘述. 关于调优目标:延迟.吞吐量 一.延迟,单次的延迟 单次的延迟关系到服务的响应时延, ...
- JAVA之G1垃圾回收器
概述 G1 GC,全称Garbage-First Garbage Collector,通过-XX:+UseG1GC参数来启用,作为体验版随着JDK 6u14版本面世,在JDK 7u4版本发行时被正式推 ...
- jvm默认的并行垃圾回收器和G1垃圾回收器性能对比
http://www.importnew.com/13827.html 参数如下: JAVA_OPTS="-server -Xms1024m -Xmx1024m -Xss256k -XX:M ...
- G1垃圾回收器参数配置
下面是完整的 G1 的 GC 开关参数列表. 选项/默认值 说明 -XX:+UseG1GC 使用 G1 (Garbage First) 垃圾收集器 -XX:MaxGCPauseMillis=n 设置最 ...
- 探索ParNew和CMS垃圾回收器
前言 上篇文章我们一起分析了JVM的垃圾回收机制,了解了新生代的内存模型,老年代的空间分配担保原则,并简单的介绍了几种垃圾回收器.详细内容小伙伴们可以去看一下我的上篇文章:秒懂JVM的垃圾回收机制. ...
随机推荐
- MyBatis多对一,一对多,多对多,一对多关联查询
一.Person实体类 1 public class Person { 2 private Integer personId; 3 private String name; 4 private Int ...
- Hibernate4.3基础知识2
一.数据库的隔离级别 脏读 不可重复读 幻读 Read uncommited Y Y Y Read commited N Y Y Repeatable read N N Y Serializabl ...
- Hibernate4.3基础知识1
一.Hibernate 开发环境搭建 4.3 1.导包 2.创建hibernate.cfg.xml配置文件 3.创建实体类 4.创建映射文件 实体类名.hbm.xml 配置文件 二.h ...
- 手把手撸套框架-Victory框架1.1 详解
目录 上一篇博客 Victory框架1.0 详解 有说道,1.0的使用过程中出现不少缺点,比如菜单不能折叠,权限没有权限组等等. 所以,我还是抽出时间在下班后,回到我的小黑屋里 完成了1.1的升级. ...
- (入门)matlab中创建和调用m文件
大学学过的一款软件,说实话没好好学,老师直接讲到高深的做仿真之类的 综合网上的教程讲述基础的matlab创建遇到的问题: 参考: 1. https://blog.csdn.net/weixin_423 ...
- 下载 Oracle Database XE 11gR2
操作系统:Windows 10 x64 第一节:下载 Oracle Database XE 11gR2 第二节:安装.验证安装 Oracle Database XE 11gR2 第三节:Oracle ...
- 【题解】小Z的袜子
期末考试结束了,来写写blog吧 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具 ...
- Nginx 配置 http 强制跳转到 https
个人真实配置 架构:Nginx 反向代理 + Nginx 前端(LNMP) 在 Nginx 反向代理的 虚拟机主机配置文件中,作如下配置: upstream ilexa_cn { server 192 ...
- Python 中 pip 工具的安装与使用
pip 是 Python 包管理工具,该工具提供了对Python 包的查找.下载.安装.卸载的功能. 目前如果你在 python.org 下载最新版本的安装包,则是已经自带了该工具. Python 2 ...
- js 基础概念
一 执行上下文 和 执行上下文栈 执行上下文:一段javascript代码执行前的准备工作 问题一:js引擎遇到怎样一段代码才会做"准备工作呢"? 可执行代码类型:全局代码.函数代 ...