G1收集器

G1算法在JDK1.9后成为JVM默认垃圾回收算法,具有并行与并发、分代收集、空间整合、可预测停顿等特点。它将Java堆划分为多个Region,通过Remembered Set避免全堆扫描。其运作大致分为初始标记、并发标记、最终标记、筛选回收几个步骤。

G1收集器

       G1算法在jdk1.9后成为了JVM的默认垃圾回收算法。G1的特点是保持高回收率的同时减少停顿。

G1具备如下特点。

  1. 并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。
  2. 分代收集:与其他收集器一样,分代概念在G1中依然得以保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。
  3. 空间整合:与CMS的“标记一清理”算法不同,G1从整体来看是基于“标记一整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
  4. 可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是Gl和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。

      在G1之前的其他收集器进行收集的范围都是整个新生代或者老年代,而G1不再是这样。使用G1收集器时,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。


      G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region/这也就是Garbage-First名称的来由)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证子G1收集器在有限的时间内可以获取尽可能高的收集效率。

      G1把内存“化整为零”的思路,以一个细节为例:把Java堆分为多个Region后,垃圾收集是否就真的能以Region为单位进行了?听起来顺理成章,再仔细想想就很容易发现问题所在:Region不可能是孤立的。一个对象分配在某个Region中,它并非只能被本Region中的其他对象引用,而是可以与整个Java堆任意的对象发生引用关系。那在做可达性判定确定对象是否存活的时候,岂不是还得扫描整个Java堆才能保证准确性?这个问题其实并非在G1中才有,只是在G1中更加突出而已。在以前的分代收集中,新生代的规模一般都比老年代要小许多,新生代的收集也比老年代要频繁许多,那回收新生代中的对象时也面临相同的问题,如果回收新生代时也不得不同时扫描老年代的话,那么Minor GC的效率可能下降不少。

       在G1收集器中,Region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set 来避免全堆扫描的。G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序在对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于不同的Region之中(在分代的例子中就是检查是否老年代中的对象引用了新生代中的对象),如果是,便通过CardTable 把相关引用信息记录到被引用对象所属的Region的Remembered Set之中。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会有遗漏。

如果不计算维护Remembered Set的操作,G1收集器的运作大致可划分为以下几个步骤:

  1. 初始标记(Initial Marking)
  2. 并发标记(Concurrent Marking)
  3. 最终标记(Final Marking)
  4. 筛选回收(Live Data Counting and Evacuation)


       G1的前几个步骤的运作过程和CMS有很多相似之处。

  1. 初始标记阶段仅仅只是标记一下GCRoots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时很短。
  2. 并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行。
  3. 最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行。
  4. 最后在筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。

通过图可以比较清楚地看到G1收集器的运作步骤中并发和需要停顿的阶段。

 

<think>好的,用户想了解如何监控G1垃圾收集器的性能和状态,包括监控方法、性能指标以及使用的JDK工具。我需要根据提供的引用资料和已有的知识来组织回答。首先,我应该回顾一下G1的特点,比如可预测的停顿时间和并发标记机制,这些在引用[1]和[3]中提到过。然后,用户可能需要具体的监控步骤和工具,比如JDK自带的工具如jstat、GC日志分析,以及可视化工具如VisualVM。引用[4]中提到了示例配置,可能和调优相关,但用户的问题是关于监控的,所以需要重点放在监控部分。性能指标方面,停顿时间、吞吐量、堆使用情况、并发阶段时间这些是关键。需要确保每个部分都有对应的JDK工具支持,比如使用jstat查看实时数据,GC日志分析来获取详细的信息,引用[2]中的字符串去重可能影响内存使用情况,可以提及。此外,引用[3]提到的并发标记线程和初始标记阶段可能需要通过日志来观察。需要分步骤回答,结构清晰,可能用列表或分段的方式。还要注意使用中文,并按照用户的要求添加引用标识,比如在提到G1特点时引用[^1],在字符串去重时引用[^2],并发标记引用[^3],调优参数引用[^4]。最后生成相关问题,可能需要包括调优方法、常见问题、与其他收集器的对比等。需要检查是否所有回答都覆盖了用户的问题,并且引用正确。</think>### G1垃圾收集器监控方法及性能指标 #### 一、监控工具与方法 1. **JDK内置工具** - **`jstat`命令**:实时查看GC状态 ```bash jstat -gcutil <pid> 1000 # 每秒输出一次堆内存使用率 jstat -gccause <pid> 2000 # 显示最近GC原因 ``` 输出指标含:Eden区使用率(E)、老年代使用率(O)、Full GC次数(FGC)等[^4] - **`jcmd`诊断命令** ```bash jcmd <pid> GC.heap_info # 获取堆内存分布 jcmd <pid> GC.run # 手动触发GC ``` 2. **GC日志分析**(需添加JVM参数) ```bash -Xlog:gc*,gc+heap=debug:file=gc.log -XX:+UseG1GC ``` 日志包含:停顿时间(`Pause Time`)、并发阶段耗时(`Concurrent Cycle`)、回收区域统计(`Heap After GC`)[^3] 3. **可视化工具** - **VisualVM**:监控内存变化曲线、线程状态 - **GCEasy**:在线分析GC日志文件,生成可视化报告 #### 二、核心性能指标 | 指标类型 | 具体参数 | 健康值参考 | |------------------|----------------------------|------------------| | 停顿时间 | `Pause Time` | <200ms[^4] | | 吞吐量 | 1 - (GC时间/总运行时间) | >90% | | 堆内存使用 | Old Gen占比 | <70%触发Mixed GC | | 并发标记效率 | Concurrent Cycle耗时 | <5秒 | | 字符串去重效率 | String Deduplication节省量 | 通过日志观察[^2] | #### 三、关键监控场景 1. **混合式GC触发条件** 通过`jstat -gc <pid>`观察老年代占用率,当达到`InitiatingHeapOccupancyPercent`阈值(默认45%)时触发并发标记[^3] 2. **内存碎片检测** 使用`jmap -histo <pid>`查看对象分布,若发现大量小对象占用老年代,需考虑调整`G1HeapRegionSize`[^4] 3. **停顿时间异常** 检查GC日志中的`Evacuation Failure`事件,可能需增加`-XX:G1ReservePercent`预留内存比例 #### 四、调优联动监控示例 当发现`Concurrent Mark`阶段耗时过长时: 1. 通过`-XX:ConcGCThreads`增加并发线程数 2. 使用`-XX:G1ConcRefinementThreads`调整并行线程数 3. 监控调整后的`Concurrent Cycle`时间变化[^3] $$ \text{吞吐量计算公式} = \frac{\text{应用运行时间} - \sum \text{GC停顿时间}}{\text{总运行时间}} \times 100\% $$
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值