前言

最近王子因为个人原因有些忙碌,导致文章更新比较慢,希望大家理解,之后也会持续和小伙伴们一起共同分享技术干货。

上篇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的区别,王子会第一时间回复。

那我们下篇文章再见。

往期文章推荐:

大白话谈JVM的类加载机制

JVM内存模型不再是秘密

轻松理解JVM的分代模型

秒懂JVM的垃圾回收机制

探索ParNew和CMS垃圾回收器

探索G1垃圾回收器的更多相关文章

  1. G1垃圾回收器

    垃圾回收器的发展历程 背景 01.G1解决的问题 G1垃圾回收器是04年正式提出,12开始正式支持,在17年作为JDK9默认的垃圾处理器. 在04年的时候,java程序堆的内存越来越大,从而导致程序中 ...

  2. 深入浅出具有划时代意义的G1垃圾回收器

    G1诞生的背景 Garbage First(简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式.HotSpot开发团队最初 ...

  3. JVM学习——G1垃圾回收器(学习过程)

    JVM学习--G1垃圾回收器 把这个跨时代的垃圾回收器的笔记独立出来. 新生代:适用复制算法 老年代:适用标记清除.标记整理算法 二娃本来看G1的时候觉得比较枯燥,但是后来总结完之后告诉我说,一定要慢 ...

  4. G1垃圾回收器在并发场景调优

    一.序言 目前企业级主流使用的Java版本是8,垃圾回收器支持手动修改为G1,G1垃圾回收器是Java 11的默认设置,因此G1垃圾回收器可以用很长时间,现阶段垃圾回收器优化意味着针对G1垃圾回收器优 ...

  5. G1 垃圾回收器简单调优

    G1: Garbage First 低延迟.服务侧分代垃圾回收器. 详细介绍参见:JVM之G1收集器,这里不再赘述. 关于调优目标:延迟.吞吐量 一.延迟,单次的延迟 单次的延迟关系到服务的响应时延, ...

  6. JAVA之G1垃圾回收器

    概述 G1 GC,全称Garbage-First Garbage Collector,通过-XX:+UseG1GC参数来启用,作为体验版随着JDK 6u14版本面世,在JDK 7u4版本发行时被正式推 ...

  7. jvm默认的并行垃圾回收器和G1垃圾回收器性能对比

    http://www.importnew.com/13827.html 参数如下: JAVA_OPTS="-server -Xms1024m -Xmx1024m -Xss256k -XX:M ...

  8. G1垃圾回收器参数配置

    下面是完整的 G1 的 GC 开关参数列表. 选项/默认值 说明 -XX:+UseG1GC 使用 G1 (Garbage First) 垃圾收集器 -XX:MaxGCPauseMillis=n 设置最 ...

  9. 探索ParNew和CMS垃圾回收器

    前言 上篇文章我们一起分析了JVM的垃圾回收机制,了解了新生代的内存模型,老年代的空间分配担保原则,并简单的介绍了几种垃圾回收器.详细内容小伙伴们可以去看一下我的上篇文章:秒懂JVM的垃圾回收机制. ...

随机推荐

  1. Centos-bash-4.1$

    错误: -bash-4.1$ where? 登录Centos时候,会显示4行这样的错误信息-bash-4.1$ why? 1. 该用户家目录缺少 .bashrc .bash_logout .base_ ...

  2. 探索与英特尔XDK

    下载Geolocation.rar - 6.3 KB 下载Abhishek3.rar - 425.1 KB 下载Abhishek3.crosswalk.x86.20140824201436.rar - ...

  3. 对lambda表达式的字节码实现个人理解 - 简单描述

    暂且抛开具体的代码实现,谈谈个人的理解. 常规的方法调用,具体由哪条指令来执行,实际都是在JVM的规则中就定下来了,比如构造方法使用invokeSpecial,静态方法使用invokeStatic.现 ...

  4. 多测师讲解selenium_输入性弹框定位_高级讲师肖sir

    #输入性弹框from selenium import webdriverfrom time import sleepdrvier=webdriver.Chrome()url='file:///F:\d ...

  5. 2020年java全套教程,此套java涵盖了pdf,java源码,项目案例,完整视频约3000G的资源

    疫情期间,百无聊赖,是不是需要充电一下,让自己更有竞争力呢?学习java一定要快呦! 废话不多说了,网盘已经爆炸了,把2006年-2020年的全部资料都发给爱学习的你吧, 希望可以改变你的命运,或者是 ...

  6. day40 Pyhton 并发编程03

    一.内容回顾 进程是计算机中最小的资源分配单位 进程与进程之间数据隔离,执行过程异步 为什么会出现进程的概念? 为了合理利用cpu,提高用户体验 多个进程是可以同时利用多个cpu的,可以实现并行的效果 ...

  7. docket镜像

    1.是什么 镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码.运行时.库.环境变量和配置文件. 1.1.什么是UnionF ...

  8. spring boot:redis+lua实现生产环境中可用的秒杀功能(spring boot 2.2.0)

    一,秒杀需要具备的功能: 秒杀通常是电商中用到的吸引流量的促销活动方式 搭建秒杀系统,需要具备以下几点: 1,限制每个用户购买的商品数量,(秒杀价格为吸引流量一般会订的很低,不能让一个用户全部抢购到手 ...

  9. php休眠微秒

    <?php $child = new \Swoole\Process(function(){ while(true){ echo date("Y-m-d H:i:s").PH ...

  10. Linux的安全模型

    3A 资源分派: Authentication:认证,验证用户身份 Authorization:授权,不同的用户设置不同权限 Accouting|Audition:审计 当用户登录成功时,系统会自动分 ...