深入浅出JVM(十八)之并发垃圾收集器G1

简介: 深入浅出JVM(十八)之并发垃圾收集器G1

在这篇文章 深入浅出JVM(十六)之三色标记法与并发可达性分析 中,我们曾说明过GC线程和用户线程并发执行导致的对象消失问题,可以使用增量更新或原始快照的方式来解决

上文深入浅出JVM(十七)之并发垃圾收集器CMS中描述过使用增量更新的CMS,本文将介绍使用原始快照的G1垃圾收集器

Garbage First

G1 全称 Garbage First 面向服务端的垃圾收集器,G1诞生是为了在延迟可控的情况下尽可能高的吞吐量

Region

G1 不再使用分代收集算法,把Java堆内存分为多个大小相等的区域(Region),面向堆内存任何部分来组成区(Region)进行收集,哪块内存垃圾最多,收益最大就回收哪块

image.png

Region分为新生代Eden、新生代Survive、大对象Humongous

大多数情况下Humongous被当成老年代

当大对象太大,一个Humongous不够时,使用连续多个Humongous存储

每个区域设计2个TAMS(Top at Mark Start)指针,把区域中一部分空间划分出来用来为新对象分配内存(指针碰撞,内存规整)

G1从整体上可以看成使用标记-整理算法,从局部上可以看成使用区域间复制算法

执行过程与流程图

G1采用原始快照来解决GC线程与用户线程并发时的对象消失问题

G1收集器在后台维护一个优先级队列跟踪各个区域中的垃圾回收价值(回收垃圾的大小和回收时间的情况)

根据-XX:MaxGCPauseMillis用户规定的收集停顿时间来优先回收垃圾回收价值最大的区域

执行过程

  1. 初始标记 : 标记GC Roots能直接关联的对象,修改TAMS指针(停顿用户线程,耗时短)
  2. 并发标记 : 从GC Roots直接关联对象开始遍历整个引用链的过程(GC线程与用户线程并发执行耗时长),扫描完还要处理原始快照记录在并发时有引用变动的对象
  3. 最终标记 : 处理并发阶段遗留下来的少量原始快照记录(停顿用户线程,耗时短)
  4. 筛选回收 : 更新区域的垃圾回收价值,把各个区域的垃圾回收价值(要算成本:回收时间)在优先级队列中排序,根据用户所期望的停顿时间制定回收计划,把要回收的那片区域存活的对象复制到空区域中(复制对象要暂停用户线程,GC线程并行执行)

如果期望停顿时间设置太短(不符合实际),由于停顿时间短,回收垃圾速度<为新对象分配内存速度,会导致堆满Full GC反而会降低性能

image.png

参数

-XX:+UseG1GC 使用G1收集器

-XX:G1HeapRegionSize设置每个region大小

-XX:MaxGCPauseMillis设置预期停顿时间 (默认200ms,最好不要太小)

-XX:ParallelGCThread设置GC线程数

-XX:ConcGCThreads设置并发标记线程数

-XX:InitiatingHeapOccupancyPercent设置触发老年代GC的堆占用率阈值

特点

优点

  1. 整体:标记-整理、局部:复制,不会产生内存碎片
  2. 从用户期望时间来回收垃圾价值最高的垃圾
  3. 原始快照的好处(记录旧引用,不需要添加新引用记录,减少并发标记、重新标记阶段的消耗)

缺点

  1. 因为有很多区域,跨区域引用对象问题频繁出现,每个区域要维护记忆集(Key:别的区域地址 Value:集合存储卡表的索引号),卡表实现复杂(其他卡表:我指向谁,这里的卡表:我指向谁+谁指向我),所以占用内存更大
  2. 执行负载大(写屏障操作复杂)
    写后屏障维护复杂的卡表
    原始快照的坏处(需要记录旧引用):写前屏障跟踪并发指针变化,在用户程序运行中产生有跟踪引用变化带来的额外负担
    CMS写屏障可以直接同步,而G1写屏障太复杂要把写前屏障和写后屏障中做的事放到队列中,异步处理

总结

本篇文章深入浅出的介绍G1并发垃圾收集器Region、执行过程、流程图、参数、特点等知识

G1不使用分代算法,将内存分为Region,Region分为Eden、Survive、Humongous,从局部可以看成复制算法,整理上看成标记-整理算法

G1初始标记枚举GC根节点,在并发标记中使用原始快照解决对象消失问题,最终标记后使用优先级队列优先回收价值高的region

G1不会产生内存碎片,能够在期望的低延迟中完成价值最大的清理,但维护跨代引用、写后屏障等开销大

内存较大、处理器较多、期望低延迟、面向服务端的垃圾收集器可以选择G1

最后(一键三连求求拉~)

本篇文章将被收入JVM专栏,觉得不错感兴趣的同学可以收藏专栏哟~

本篇文章笔记以及案例被收入 gitee-StudyJavagithub-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

相关文章
|
2月前
|
存储 算法 Oracle
极致八股文之JVM垃圾回收器G1&ZGC详解
本文作者分享了一些垃圾回收器的执行过程,希望给大家参考。
|
2月前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
2月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
19 3
|
2月前
|
C# UED 开发者
WPF打印功能实现秘籍:从页面到纸张,带你玩转WPF打印技术大揭秘!
【8月更文挑战第31天】在WPF应用开发中,打印功能至关重要,不仅能提升用户体验,还增强了应用的实用性。本文介绍WPF打印的基础概念与实现方法,涵盖页面元素打印、打印机设置及打印预览。通过具体案例,展示了如何利用`PrintDialog`和`PrintDocument`控件添加打印支持,并使用`PrinterSettings`类进行配置,最后通过`PrintPreviewWindow`实现打印预览功能。
94 0
|
2月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
62 0
|
2月前
|
算法 Java 程序员
【JVM的秘密花园】揭秘垃圾收集器的神秘面纱!
【8月更文挑战第25天】在Java虚拟机(JVM)中,垃圾收集(GC)自动管理内存,回收未使用的对象以避免内存泄漏和性能下降。本文深入介绍了JVM中的GC算法,包括串行、并行、CMS及G1等类型及其工作原理。选择合适的GC策略至关重要:小型应用适合串行收集器;大型应用或多核CPU环境推荐并行收集器或CMS;需减少停顿时间时,CMS是好选择;G1适用于大堆且对停顿时间敏感的应用。理解这些能帮助开发者优化程序性能和稳定性。
29 0
|
2月前
|
监控 JavaScript Java
JVM源码级别分析G1发生FullGC元凶的是什么
线上系统遭遇频繁Old GC问题,监控显示出现多次“to-space exhausted”日志,这表明垃圾回收过程中因年轻代 Survivor 区或老年代空间不足导致对象晋升失败。通过 JVM 源码分析,此问题源于对象转移至老年代失败时,JVM 无法找到足够的空间存放存活对象。进一步排查发现大对象分配占用了预留空间,加剧了空间不足的情况。使用 JFR 分析工具定位到定期报表序列化导致大量大对象生成,通过改用堆外内存进行序列化输出,最终解决了频繁 Old GC 问题。
|
2月前
|
算法 Java
JVM自动内存管理之垃圾收集器
这篇文章是关于Java虚拟机(JVM)自动内存管理中的垃圾收集器的详细介绍。
|
2月前
|
Java Docker 索引
记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
这篇文章记录了作者在分布式微服务项目中遇到的一系列问题,起因是商品服务检索接口测试失败,原因是Elasticsearch索引未找到。文章详细描述了解决过程中遇到的几个关键问题:分词器的安装、Elasticsearch内存溢出的处理,以及最终成功创建`gulimall_product`索引的步骤。作者还分享了使用Postman测试接口的经历,并强调了问题解决过程中遇到的挑战和所花费的时间。
|
4天前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
13 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制