深入理解JVM中的G1垃圾收集器原理、过程和参数配置

码到三十五 : 个人主页

心中有诗画,指尖舞代码,目光览世界,步履越千山,人间尽值得 !

在Java虚拟机(JVM)中,垃圾收集(GC)是一个自动管理内存的过程,旨在回收不再使用的对象所占用的内存空间。G1垃圾收集器(G1 GC)是JVM中的一种重要垃圾收集器,尤其适用于需要低延迟和可预测停顿时间的大型应用程序。本文将深入探讨G1垃圾收集器的工作原理、关键特性和性能优化建议。

目录

    • 一、G1收集器概述
      • 主要特点
    • 二、G1分区划分
    • 三、为什么G1收集器需要设计巨型对象
    • 四、G1收集器的回收过程
    • 五、G1的两种回收策略
      • 5.1 Young GC(新生代回收)
      • 5.2 Mix GC(混合回收)
    • 六、跨代引用和RSet(记忆集)
    • 七、性能优化建议
    • 八、G1核心配置参数
    • 九、结语

一、G1收集器概述

G1收集器(Garbage-First Garbage Collector,简称G1 GC)是Java虚拟机(JVM)中的一种垃圾收集器,专为服务器端应用设计,特别适用于具有多核处理器和大内存的机器。G1 GC在JDK 7u4版本中被正式推出,并且在JDK 9中成为默认的垃圾收集器。它的主要目标是在满足高吞吐量的同时,尽可能缩短垃圾收集造成的停顿时间。

主要特点

  1. 并行与并发:G1 GC能够充分利用多核处理器的优势,通过并行执行垃圾收集任务来提高效率。同时,它的大部分工作都是与应用线程并发执行的,从而减少了停顿时间。
  2. 分区域收集:G1 GC将整个堆内存划分为多个大小相等的独立区域(Region),这些区域在逻辑上是连续的,但在物理内存上可能不是连续的。每个Region都可以扮演Eden区、Survivor区或Old区等角色。这种设计使得G1 GC能够更加灵活地进行内存管理和垃圾收集。
  3. 优先回收垃圾最多区域:G1 GC通过跟踪每个Region中的垃圾堆积情况,并根据回收价值和成本进行排序,优先回收垃圾最多的Region。这种策略有助于最大限度地提高垃圾收集的效率。
  4. 可预测的停顿时间:G1 GC通过建立一个可预测的停顿时间模型,允许用户明确指定在一个特定时间片段内,垃圾收集所造成的停顿时间不得超过某个阈值。这使得G1 GC非常适合需要严格控制停顿时间的应用场景。
  5. 使用标记-整理算法:在整体上,G1 GC使用标记-整理算法来回收内存,以减少内存碎片的产生。但在两个Region之间进行垃圾收集时,它则采用标记-复制算法。这种组合策略有助于兼顾内存利用率和垃圾收集效率。

二、G1分区划分

G1收集器的分区划分是其核心特性之一,它允许G1更灵活、高效地管理内存和执行垃圾回收:

  1. 基本思想
    G1收集器将整个Java堆划分为多个大小相等、独立的区域,这些区域被称为“Region”。每个Region的大小可以根据堆空间的实际大小而定,通常在1MB到32MB之间,且必须是2的N次幂。这意味着Region的大小可以是1MB、2MB、4MB、8MB、16MB或32MB。默认情况下,整个堆空间被划分为约2048个这样的Region。

  2. 分区类型
    G1的Region可以根据其用途和状态分为不同类型。主要包括:

    • 自由分区(Free Heap Region, FHR):这些Region当前没有包含任何对象,是空闲的,可以用于新的对象分配。
    • 新生代分区(Young Heap Region, YHR):这些Region被划分为新生代,包括Eden区和Survivor区。新生代分区主要用于存储新创建的对象。
    • 大对象分区(Humongous Heap Region, HHR):专门用于存储大对象。在G1中,只要对象的大小超过了一个Region容量的一半,就被认为是大对象。这些对象会被直接分配到Humongous Region中,且每个大对象都单独占用一个或多个连续的Humongous Region。
    • 老年代分区(Old Heap Region, OHR):这些Region被划分为老年代,用于存储长时间存活的对象。

在这里插入图片描述

  1. 分区的管理和回收
    G1收集器通过维护一个优先列表来跟踪各个Region中的垃圾堆积情况和回收价值。在垃圾回收过程中,G1会根据这个列表优先回收价值最大的Region。这种策略使得G1能够更有效地利用处理器资源,并最大限度地减少垃圾回收造成的停顿时间。

  2. 优点
    G1的分区划分带来了几个显著优点。首先,它允许更细粒度的内存管理,提高了内存的利用率。其次,通过优先回收垃圾最多的Region,G1能够保持较高的吞吐量并缩短停顿时间。最后,G1的分区策略使其能够很好地适应不同的内存大小和垃圾回收需求。

三、为什么G1收集器需要设计巨型对象

G1收集器需要设计巨型对象(Humongous Objects)主要是出于对内存管理和垃圾收集效率的考虑。在G1收集器的设计中,整个堆内存被划分为多个大小相等的区域(Region),每个Region用于存放对象。然而,有些对象的大小可能会超过一个Region的容量,这就引出了巨型对象的概念。

巨型对象是指那些大小超过了一个Region容量50%以上的对象。由于这些对象太大,无法完整地存放在一个Region中,因此需要特殊处理。G1收集器通过引入巨型对象的概念,并为之设计专门的存储和管理机制,确保了这些大对象能够被有效地管理和回收。

具体来说,巨型对象在G1中被直接分配到特殊的Humongous Region中,每个巨型对象可以独占一个或多个连续的Humongous Region。这样做的好处是可以避免由于对象跨Region存储而导致的复杂性和性能开销。同时,G1收集器还会针对巨型对象进行特殊的垃圾回收策略,以提高垃圾收集的效率和整个系统的性能。

此外,巨型对象的设计也考虑到了应用的实际情况和需求。在实际应用中,往往存在一些需要占用大量内存的大对象,如大型的数组、数据结构等。如果不对这些大对象进行特殊处理,它们可能会对整个垃圾收集器的性能和内存利用率造成负面影响。因此,G1收集器通过设计巨型对象及其管理机制来应对这一挑战。

综上所述,G1收集器需要设计巨型对象主要是为了更有效地管理大内存对象,提高垃圾收集效率和整个系统的性能。

四、G1收集器的回收过程

G1收集器的回收过程主要包括以下几个步骤:

  1. 初始标记(Initial Marking)
    这个过程是STW(Stop-The-World)的,但通常耗时非常短。它标记出从GC Roots直接可达的对象,作为后续垃圾收集的基础。

  2. 并发标记(Concurrent Marking)
    在初始标记完成后,G1 GC会进入并发标记阶段。这个阶段与应用程序线程并发执行,通过递归地追踪所有可达的对象,并将它们标记为存活。这个过程是并发的,因此不会阻塞应用程序的执行。

  3. 最终标记(Final Marking)
    为了处理在并发标记过程中新产生的对象引用关系,G1 GC会执行一次短暂的STW的最终标记。这个阶段确保所有在并发标记阶段漏掉的对象都被正确标记。

  4. 筛选回收(Live Data Counting and Evacuation)
    在这个阶段,G1 GC会根据每个Region的垃圾堆积情况和回收价值进行排序,并选择性地回收部分Region中的垃圾对象。回收过程包括将存活的对象从一个Region复制或移动到另一个Region,并更新相关的引用。这个过程也是并发的,旨在最大限度地减少停顿时间。同时,这个阶段可能会涉及到对象的整理和压缩,以减少内存碎片。

此外,G1收集器还采用了分区(Region)的方式来管理内存,每个Region都被标记了不同的状态(如Eden、Survivor、Old等)。这种设计使得G1能够更灵活地进行内存分配和垃圾回收,从而提高了整体的效率和性能。

值得注意的是,G1收集器还提供了两种主要的垃圾回收模式:Young GC和Mixed GC。Young GC主要负责回收新生代中的垃圾对象,而Mixed GC则负责回收新生代和部分老年代中的垃圾对象。这两种模式都是根据堆内存的使用情况和GC的触发条件来自动选择的。

五、G1的两种回收策略

G1垃圾收集器是Java虚拟机(JVM)中的一个重要组件,它提供了两种主要的垃圾回收策略:Young GC(新生代回收)和Mix GC(混合回收)。这两种策略在回收对象和回收区域上有所不同,但都是为了提高垃圾回收的效率,减少停顿时间,从而提升应用程序的性能。

5.1 Young GC(新生代回收)

Young GC主要负责回收新生代中的对象。新生代通常包含新创建的对象,这些对象更有可能在短时间内变成垃圾。Young GC的执行过程相对较快,因为它只涉及新生代中对象的扫描和回收。

在Young GC过程中,Eden区和Survivor区的存活对象会被复制到另一个Survivor区或者晋升到老年代。这个过程是Stop-The-World(STW)的,意味着在回收过程中,应用程序的所有线程都会被暂停。但是,由于新生代中的对象通常较少,因此这个暂停时间通常较短,对应用程序的性能影响也较小。

5.2 Mix GC(混合回收)

Mix GC则是G1收集器特有的回收策略,它不仅回收新生代中的所有Region,还会回收部分老年代中的Region。这种策略的目标是在保证停顿时间不超过预期的情况下,尽可能地回收更多的垃圾对象。

在Mix GC过程中,首先会进行全局并发标记(global concurrent marking),这个过程是并发的,与应用程序线程同时执行,用于标记出所有存活的对象。然后,在回收阶段,G1会根据标记结果选择收益较高的部分老年代Region和新生代Region一起进行回收。这个选择过程是基于对Region中垃圾对象的数量和回收价值的评估。

与Young GC不同,Mix GC的停顿时间可能会更长,因为它涉及到对老年代中对象的扫描和回收。但是,由于Mix GC能够回收更多的垃圾对象,因此它通常能够更有效地释放内存空间,减少垃圾堆积对应用程序性能的影响。

六、跨代引用和RSet(记忆集)

在垃圾收集过程中,跨代引用或跨Region引用是一个需要特别注意的现象:

  1. 跨代引用的概念
    在垃圾收集领域,跨代引用指的是不同代际之间的对象相互引用。在G1收集器中,由于堆被划分为多个Region,跨代引用通常表现为跨Region引用。年轻代指向老年代的引用在垃圾收集中不是主要问题,因为即使年轻代的对象被清理,程序仍然可以正常运行,且未被标记到的老年代对象会在后续的Major GC中被回收。

  2. 老年代指向年轻代的引用问题
    当存在老年代指向年轻代的引用时,情况就复杂了。在Minor GC阶段,我们不能简单地清理年轻代中的对象,因为老年代中可能还有对象持有对这些对象的引用。为了解决这个问题,我们需要一种机制来跟踪这些跨Region的引用。

  3. RSet(记忆集)的作用
    RSet正是为了解决这个问题而设计的。它的主要作用是记录哪些Region中的老年代对象有指向年轻代的引用。在GC时,通过扫描这些Region中的RSet,我们可以快速识别出需要保留的年轻代对象,从而避免扫描整个老年代,显著提高了垃圾收集的效率。RSet的实现本质上是一种哈希表,其中Key是Region的起始地址,Value是一个集合,存储了卡表的索引号。

RSet(RememberedSet)是一个非常重要的数据结构,用于记录并跟踪其他Region指向当前Region中对象的引用。在G1收集器的分区模型中,由于堆内存被划分为多个独立的Region,对象之间的引用关系可能跨越不同的Region。为了能够在垃圾收集过程中正确地识别和处理这些跨Region的引用,G1引入了RSet的概念。

每个Region都有一个与之关联的RSet,用于记录其他Region中指向该Region内对象的引用信息。当发生对象引用关系变化时,G1会更新相应的RSet,以确保垃圾收集的准确性。在垃圾收集过程中,G1会利用RSet来快速确定哪些Region之间存在引用关系,从而避免不必要的全堆扫描,提高垃圾收集的效率。

RSet的实现通常涉及一些优化技术,如使用位图(Bitmaps)或压缩表(CompressedTables)来紧凑地存储引用信息,以减少内存占用和提高访问速度。此外,G1还采用了一些策略来维护RSet的一致性,如在并发标记阶段使用写屏障(Write Barriers)来拦截并更新跨Region的引用。

  1. 减少YGC时的扫描开销
    由于新生代的垃圾收集通常很频繁(即YGC),如果每次都需要扫描整个老年代来确定是否有对新生代的引用,那么开销将会非常大。通过RSet的跟踪机制,我们可以精确地知道哪些老年代Region中的对象引用了新生代对象,从而只扫描这些Region,大大降低了YGC时的扫描开销。

  2. 卡标记(Card Marking)技术与卡表(Card Table)
    HotSpot JVM为了更高效地处理老年代到新生代的引用问题,采用了卡标记技术。具体来说,它使用了一个称为卡表(Card Table)的数据结构来辅助标记过程。堆空间被划分为一系列的卡页(Card Page),每个卡页对应卡表中的一个标记项。当发生对老年代到新生代引用的写操作时,通过写屏障(Write Barrier)机制来更新卡表中对应的标记项。这样,在GC时,我们只需要扫描那些被标记为dirty的卡页所对应的Region即可快速找到所有老年代到新生代的引用关系。

七、性能优化建议

  1. 合理设置堆大小:根据应用程序的内存需求和硬件资源,合理设置JVM的堆大小。过大的堆可能会导致长时间的垃圾收集停顿,而过小的堆则可能导致频繁的垃圾收集。

  2. 调整停顿时间目标:通过调整G1的停顿时间目标(-XX:MaxGCPauseMillis参数),可以平衡垃圾收集的效率和应用程序的响应时间。在需要低延迟的场景中,可以设置较短的停顿时间目标。

  3. 启用并行垃圾收集线程:通过增加并行垃圾收集线程的数量(-XX:ParallelGCThreads参数),可以提高垃圾收集的效率。然而,过多的线程可能会导致系统资源的竞争和额外的开销,因此需要谨慎调整。

  4. 优化对象分配和晋升策略:通过优化对象的分配和晋升策略,可以减少新生代和老年代之间的对象流动,从而降低垃圾收集的开销。例如,可以考虑使用对象池、缓存等技术来减少临时对象的创建和销毁。

  5. 监控和分析GC日志:定期监控和分析GC日志可以帮助识别潜在的内存泄漏、性能瓶颈和优化机会。可以使用JVM自带的工具(如jstat、jvisualvm)或第三方工具(如GCViewer、YourKit)来进行日志分析和性能调优。

八、G1核心配置参数

在JDK9及以后的版本中,G1是默认的垃圾收集器,但在JDK8中,你需要显式地启用。以下是G1收集器的一些核心配置参数:

  1. -XX:+UseG1GC:
    这个参数用于启用G1垃圾收集器。在JDK8中,你需要明确设置这个参数来使用G1,而在JDK9及更高版本中,G1是默认启用的。

  2. -XX:G1HeapRegionSize:
    这个参数用于设置每个Region的大小。Region是G1收集器管理内存的基本单位。该值必须是2的幂,范围在1MB到32MB之间。G1的目标是根据最小的Java堆大小划分出约2048个这样的区域。默认情况下,这个值是堆内存的1/2000,这意味着G1收集器管理的最小堆内存应该是2GB以上,最大堆内存为64GB。

  3. -XX:MaxGCPauseMillis:
    这个参数用于设置期望的最大GC停顿时间指标。G1收集器会尽力在这个时间内完成垃圾回收,以减少应用程序的停顿时间。默认值是200毫秒。

  4. -XX:ParallelGCThreads:
    这个参数用于设置并行垃圾回收的线程数。这个值通常设置为与可用的CPU核心数相等,最大可以设置为8。

  5. -XX:ConcGCThreads:
    这个参数用于设置并发标记的线程数。并发标记是G1收集器在垃圾回收过程中的一个阶段,这个阶段与应用程序线程并发执行。通常,这个值设置为并行垃圾回收线程数(ParallelGCThreads)的1/4左右。

  6. -XX:InitiatingHeapOccupancyPercent:
    这个参数用于设置触发并发GC周期的Java堆占用率阈值。当堆内存的占用率达到这个值时,G1收集器会启动一个并发GC周期。默认值是45%,这意味着当堆内存的45%被占用时,就会触发垃圾回收。

  7. -XX:+PrintGCDetails-verbose:gc:
    这两个参数不是G1特有的,但它们对于调试和监控垃圾收集器的行为非常有用。-XX:+PrintGCDetails会打印详细的垃圾收集日志,包括每次垃圾收集的时间、回收的对象数量等信息。-verbose:gc则会启用垃圾收集的日志记录,通常与-XX:+PrintGCDetails一起使用以获取更全面的日志输出。

在这里插入图片描述

九、结语

G1垃圾收集器以其可预测的停顿时间、灵活的内存管理和高效的并发标记等特点,在JVM中占据了重要的地位。通过深入理解G1的工作原理和关键特性,并根据实际应用场景进行性能优化,我们可以更好地利用G1来提升Java应用程序的性能和响应时间。



听说...关注下面公众号的人都变牛了,纯技术,纯干货 !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/823601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第四套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第四套 (共9套,有答案和解析,答案非官方,仅供参考)(共九套,每套四十个选择题) 部分题目分享,完整版获取(WX:didadida…

「GO基础」起源与演进

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

一文讲明白什么是市场调研

本文主要介绍市场调研的主要步骤和工具方法,并简单介绍了淘宝在电商领域中市场调研的实践。 什么是调研 ▐ 定义 广义的含义,调研既是指市场调查,通过收集、分析和解释相关数据来达到了解企业现状、了解市场趋势、挖掘用户需求、确定产品研发…

『哈哥赠书 - 51期』-『数字风控体系:设计与实践』

⭐️ 赠书 - 《数字风控体系:设计与实践》 ⭐️ 数字风控概述 从2007年开始到2014年左右,高速移动网络和智能手机迅速在大众中普及,开启了移动互联网时代。在这个背景下,企业的产品与服务也出现了两个重要的趋势。 第一个趋势是…

VUE3 + Elementui-Plus 之 树形组件el-tree 一键展开(收起);一键全选(不全选)

需求&#xff1a; 产品要求权限树形结构添加外部复选框进行全部展开或收起&#xff1b;全选或不全选。 实现步骤&#xff1a; tree组件部分&#xff1a; <div class"role-handle"><div>权限选择(可多选)</div><div><el-checkbox v-mode…

Git回滚版本并push到远端master

1、查看日志 git log 2、还原最近的版本 () --git reset --hard commit-id 如&#xff1a;git reset --hard d84da14bf2743683eca7a015f56114faaa344f42 3、覆盖分支版本 git push -f origin dev 回滚本地master完成后&#xff0c;将回滚后的代码push到远端master&#xf…

C++笔记:异常

文章目录 C 运行时错误处理机制及其不足之处C 异常概念异常的使用异常的抛出和匹配原则在函数调用链中异常栈展开匹配原则异常的重新抛出举例演示说明例子一&#xff1a;串联举例演示大部分原则例子二&#xff1a;模拟服务器开发中常用的异常继承体系例子三&#xff1a;异常的重…

C++初级----list(STL)

1、 list介绍 1.1、 list介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 1. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向 其前一…

集成定制化软件的销售推广渠道有哪些?

集成定制化软件的销售推广渠道可以包括以下几个方面&#xff1a; 一、线上渠道&#xff1a; 官方网站&#xff1a;建立专业的官方网站&#xff0c;展示软件的功能、优势、案例等&#xff0c;提供试用或购买链接。社交媒体&#xff1a;利用微博、微信、抖音等社交媒体平台&#…

SpringBoot中的动态编程实战原来是这么玩的

Java 开发已经有越来越多的 Groovy 出现在后台了。 而对于一般的应用开发&#xff0c;只要能用 Java 就都能用到 Groovy&#xff0c;唯一的难点只在于能不能招到足够的人员。 注&#xff1a;今天我们分享的就是利用Groovy脚本在SpringBoot项目中实现动态编程&#xff0c;使业务…

【YOLOv8改进[Neck]】使用BiFPN助力V8更优秀

目录 一 BiFPN(双向特征金字塔网络) 1 BiFPN 2 EfficientDet 二 使用BiFPN助力模型更优秀 1 整体修改 2 配置文件 3 训练 其他 一 BiFPN(双向特征金字塔网络) BiFPN(双向特征金字塔网络&#xff0c; 2020)用于特征融合层。 官方论文地址&#xff1a;https://arxiv.org…

鸢尾花数据集分类(决策树,朴素贝叶斯,人工神经网络)

目录 一、决策树 二、朴素贝叶斯 三、人工神经网络 四、利用三种方法进行鸢尾花数据集分类 一、决策树 决策树是一种常用的机器学习算法&#xff0c;用于分类和回归任务。它是一种树形结构&#xff0c;其中每个内部节点表示一个特征或属性&#xff0c;每个分支代表这个特征…

Spring容器结构

文章目录 1.基本介绍1.Spring5官网2.API文档3.Spring核心学习内容4.几个重要概念 2.快速入门1.需求分析2.入门案例1.新建Java项目2.导入jar包3.编写Monster.java4.src下编写Spring配置文件1.创建spring配置文件&#xff0c;名字随意&#xff0c;但是需要放在src下2.创建Spring …

SparkUI 讲解

目录 Executors Environment Storage SQL Exchange Sort Aggregate Jobs Stages Stage DAG Event Timeline Task Metrics Summary Metrics Tasks &#x1f490;&#x1f490;扫码关注公众号&#xff0c;回复 spark 关键字下载geekbang 原价 90 元 零基础入门 Spar…

IDEA2023 开发环境配置

目录 1. 关闭IDEA自动更新1.2 IDEA 新版样式切换 2. Maven配置2.1本地仓库优先加载2.2 maven.config配置文件中 3. 全局配置JDK4. 配置文件编码:UTF-85. 开启自动编译&#xff08;全局配置&#xff09;6. 开启自动导包7. 开启鼠标悬浮&#xff08;提示文档信息&#xff09;8. 设…

golang 使用栈模拟计算器

思路&#xff1a; // Author sunwenbo // 2024/4/12 16:51 package mainimport ("errors""fmt""strconv" )// 使用数组来模拟一个栈的应用 type Stack struct {MaxTop int //表示栈最大可以存放数的个数Top int //表示栈底&#xff…

2024年阿里云4核8G配置云服务器价格低性能高!

阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云优惠 aliyunfuwuqi…

代码随想录算法训练营第二十九天|491.递增子序列、46.全排列、46.全排列II

491. 非递减子序列 思路&#xff1a; 在90.子集II (opens new window)中我们是通过排序&#xff0c;再加一个标记数组来达到去重的目的。 而本题求自增子序列&#xff0c;是不能对原数组进行排序的&#xff0c;排完序的数组都是自增子序列了。 所以不能使用之前的去重逻辑&…

【模拟】Leetcode 数青蛙

题目讲解 1419. 数青蛙 算法讲解 class Solution { public:int minNumberOfFrogs(string croakOfFrogs) {string target "croak";int n target.size();//保存target每个字符的位置indexunordered_map<char, int>index;for(int i 0; i < n; i)index[tar…

必应Bing国内广告推广,帮助企业降低获客成本!

搜索引擎广告作为数字营销的重要手段之一&#xff0c;因其精准定位和效果可衡量而备受青睐。而在众多搜索引擎平台中&#xff0c;必应Bing以其独特的市场定位和用户群体成为不可忽视的广告推广渠道。云衔科技作为一家专业的数字营销服务提供商&#xff0c;致力于帮助企业实现高…