JVM基础(6)——G1收集器及G1日志分析

来源:互联网 发布:新网域名管理密码 编辑:程序博客网 时间:2024/06/01 08:34

系列文章规划:

  1. JVM基础(1)——内存模型
  2. JVM基础(2)——内存管理
  3. JVM基础(3)——编译机制
  4. JVM基础(4)——类加载机制
  5. JVM基础(5)——垃圾回收和调优
  6. JVM基础(6)——G1收集器及G1日志分析
  7. JVM基础(7)——jdk常用内置工具

1. G1简介

1.1 概述

G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多核处理器及大容量内存的机器。
在极大概率满足GC停顿时间要求的同时,还具备高吞吐量的特性.。Oracle JDK 7 update 4 及以上版本已完全支持。其设计目标如下:

  • 可以像CMS收集器一样,GC操作与应用的线程一起并发执行;
  • 紧凑的空闲内存区间且没有很长的GC停顿时间;
  • 需要更多可预测的GC停顿时间;
  • 不想牺牲太多吞吐量性能;
  • 启动后不需要请求更大的Java堆。

G1的长期目标是取代CMS(Concurrent Mark-Sweep Collector, 并发标记-清除)。因为特性的不同,G1成为比CMS更好的解决方案。其中一个区别是,G1是一款压缩型的收集器。G1通过有效的压缩完全避免了对细微空闲内存空间的分配,不用依赖于regions,这不仅大大简化了收集器,而且还消除了潜在的内存碎片问题。除压缩以外,G1的垃圾收集停顿也比CMS容易估计,也允许用户自定义所希望的停顿参数(pause targets)。

内存占用

如果从 ParallelOldGC 或者 CMS收集器迁移到 G1,可能会看到JVM进程占用更多的内存(a larger JVM process size)。 这在很大程度上与 “accounting” 数据结构有关,如 Remembered Sets 和 Collection Sets。

  • Remembered Sets 简称 RSets。跟踪指向某个heap区内的对象引用。 堆内存中的每个区都有一个 RSet。 RSet 使heap区能并行独立地进行垃圾集合。 RSets的总体影响小于5%。

  • Collection Sets 简称 CSets。收集集合, 在一次GC中将执行垃圾回收的heap区。GC时在CSet中的所有存活数据(live data)都会被转移(复制/移动)。集合中的heap区可以是 Eden, survivor, 和/或 old generation。CSets所占用的JVM内存小于1%。

推荐使用G1的场景

G1的首要目标是为需要大量内存的系统提供一个保证GC低延迟的解决方案。 也就是说堆内存在6GB及以上,稳定和可预测的暂停时间小于0.5秒。

如果应用程序具有如下的一个或多个特征,那么将垃圾收集器从CMS或ParallelOldGC切换到G1将会大大提升性能。

  • Full GC 次数太频繁或者消耗时间太长.
  • 对象分配的频率或代数提升(promotion)显著变化.
  • 受够了太长的垃圾回收或内存整理时间(超过0.5~1秒)

注意: 如果正在使用CMS或ParallelOldGC,而应用程序的垃圾收集停顿时间并不长,那么建议继续使用现在的垃圾收集器。使用最新的JDK时,并不要求切换到G1收集器。

1.2 G1内存结构

G1堆由多个区(region)组成,每个区大小1M~32M,逻辑上区有3种类型,包括(Eden、Survivor、Old),按分代划分包括:年轻代(Young Generation)和老年代(Old Generation)。

这里写图片描述

年轻代由非连续区组成,可以很方便的进行年轻代大小修改。

1.3 Young GC

Young GC是stop-the-world活动,会导致整个应用线程的停止。其过程如下:

  • 新对象进入Eden区
  • 存活对象拷贝到Survivor区;
  • 存活时间达到年龄阈值时,对象晋升到Old区。

young gc是多线程并行执行的。

这里写图片描述

1.4 Old GC

Old GC包含以下阶段(其中有些阶段是属于Young GC的):

  • 初始并行阶段(Initial Marking Phase)
  • Root区扫描(Root Region Scanning)
  • 并行标记(Concurrent Marking)
  • 重标记(Remark)
  • 清除(Cleanup)
  • 复制(Copying)

这里写图片描述

  1. 初始并行阶段(Initial Marking Phase)
    属于Young GC范畴,是stop-the-world活动。对持有老年代对象引用的Survivor区(Root区)进行标记。

  2. Root区扫描(Root Region Scanning)
    扫描Survivor区中的老年代对象引用,该阶段发生在应用运行时,必须在Young GC前完成。

  3. 并行标记(Concurrent Marking)
    找出整个堆中存活的对象,对于空区标记为“X”。该阶段发生在应用运行时,同时该阶段活动会被Young GC打断。

  4. 重标记(Remark)
    清除空区,重计算所有区的存活状态(liveness),是stop-the-world活动。

  5. 清除(Cleanup)

    • 选择出存活状态低的区进行收集。
    • 计算存活对象和空区,是stop-the-world活动。
    • 更新记录表,是stop-the-world活动。
    • 重置空区,将其加入空闲列表,是并行活动。
  6. 复制(Copying)

    • 该阶段是stop-the-world活动,负责将存活对象复制到新的未使用的区。
    • 可以发生在年轻代区,日志记录为[GC pause (young)]。
    • 也可以同时发生在年轻代区和老年代区,日志记录为[GC Pause (mixed)]。

2. 配置G1

//TODO

3. 日志分析

G1的调优需要利用日志信息,但首先我们需要收集到日志并能理解日志信息。

3.1 日志格式

3种日志详情格式:

  • -verbosegc。和-XX:+PrintGC等效,日志级别为fine。
  • -XX:+PrintGCDetails。日志级别为finer,包含的信息比较完整。
  • -XX:+UnlockExperimentalVMOptions -XX:G1LogLevel=finest。日志级别为finest,包含finer信息以及每个工作线程的信息。

2种时间戳格式:

  • -XX:+PrintGCTimeStamps。毫秒时间。
  • -XX:+PrintGCDateStamps。日期时间。

-XX:+PrintGCDetails日志示例:

0.522: [GC pause (young), 0.15877971 secs]                                          // 程序运行0.522秒后发生一个Evacuation Pause,耗时0.15877971秒。       [Parallel Time: 157.1 ms]                                                    // 并行GC耗时157.1 ms                   [GC Worker Start (ms):  522.1  522.2  522.2  522.2                        // 每个工作线程启动时间,时间根据线程id排序           Avg: 522.2, Min: 522.1, Max: 522.2, Diff:   0.1]                         // 所有工作线程启动时间的平均值、最小值、最大值、差别          [Ext Root Scanning (ms):  1.6  1.5  1.6  1.9                              // 每个扫描root的线程耗时           Avg:   1.7, Min:   1.5, Max:   1.9, Diff:   0.4]                                   [Update RS (ms):  38.7  38.8  50.6  37.3                                  // 每个执行更新RS(Remembered Sets)的线程的耗时           Avg:  41.3, Min:  37.3, Max:  50.6, Diff:  13.3]                                      [Processed Buffers : 2 2 3 2                                           // 每个工作线程执行UB(Update Buffers)的数量              Sum: 9, Avg: 2, Min: 2, Max: 3, Diff: 1]                                        [Scan RS (ms):  9.9  9.7  0.0  9.7                                        // 每个工作线程扫描RS的耗时           Avg:   7.3, Min:   0.0, Max:   9.9, Diff:   9.9]                                   [Object Copy (ms):  106.7  106.8  104.6  107.9                            // 每个工作线程执行OC(Object Copy)的耗时           Avg: 106.5, Min: 104.6, Max: 107.9, Diff:   3.3]                                   [Termination (ms):  0.0  0.0  0.0  0.0                                    // 每个工作线程执行终止的耗时           Avg:   0.0, Min:   0.0, Max:   0.0, Diff:   0.0]             [Termination Attempts : 1 4 4 6                                        // 每个工作线程执行终止的重试的次数              Sum: 15, Avg: 3, Min: 1, Max: 6, Diff: 5]          [GC Worker End (ms):  679.1  679.1  679.1  679.1                          // 每个工作线程终止时的时间           Avg: 679.1, Min: 679.1, Max: 679.1, Diff:   0.1]          [GC Worker (ms):  156.9  157.0  156.9  156.9                              // 每个工作线程的生命时间           Avg: 156.9, Min: 156.9, Max: 157.0, Diff:   0.1]          [GC Worker Other (ms):  0.3  0.3  0.3  0.3                                // 每个工作线程执行其他任务(上述未统计的内容)的耗时           Avg:   0.3, Min:   0.3, Max:   0.3, Diff:   0.0]       [Clear CT:   0.1 ms]                                                         // 清理CT(Card Table)的耗时       [Other:   1.5 ms]                                                            // 其他任务(上述未统计的内容)的耗时          [Choose CSet:   0.0 ms]                                                   // 选择分区的耗时          [Ref Proc:   0.3 ms]                                                      // 执行关联(Reference objects)的耗时          [Ref Enq:   0.0 ms]                                                       // 将references放入ReferenceQueues的耗时          [Free CSet:   0.3 ms]                                                     // 释放CS(collection set)的耗时       [Eden: 12M(12M)->0B(10M) Survivors: 0B->2048K Heap: 13M(64M)->9739K(64M)]    // Eden容量为12M,使用了12M,GC后变为0,容量目标大小增加到13M。                                                                                    // SurvivorsGC前为0,GC后变为2048K                                                                                    // GC前,Heap容量为64M,使用13M;GC后,Heap容量为64M,使用9739k。     [Times: user=0.59 sys=0.02, real=0.16 secs]

4. 调优

//TODO

参考文档

  1. Getting Started with the G1 Garbage Collector
  2. Garbage First Garbage Collector Tuning
  3. Java HotSpot Garbage Collection
  4. Understanding G1 GC Logs
0 0
原创粉丝点击