G1垃圾回收器--未完待续

堆空间被分割成大约2048个区域。region大小是2的次幂,最小1M,最大不超过32M,它的大小是在jvm初始化的时候就计算出来了,一旦计算出来以后就固定不变了,这个值jdk1.7与jdk1.8中的算法是不一样的;
jdk7中region计算的源码:
http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/gc_implementation/g1/heapRegion.cpp
计算公式如下:

// Minimum region size; we won't go lower than that.

// We might want to decrease this in the future, to deal with small

// heaps a bit more efficiently.
//最小的region大小
#define MIN_REGION_SIZE  (      1024 * 1024 )


// Maximum region size; we don't go higher than that. There's a good

// reason for having an upper bound. We don't want regions to get too

// large, otherwise cleanup's effectiveness would decrease as there

// will be fewer opportunities to find totally empty regions after

// marking.
//最大的region大小
#define MAX_REGION_SIZE  ( 32 * 1024 * 1024 )


// The automatic region size calculation will try to have around this

// many regions in the heap (based on the min heap size).
//期望regions区域个数,只是期望,一般不会是2048
#define TARGET_REGION_NUMBER          2048


void HeapRegion::setup_heap_region_size(uintx min_heap_size) {

  // region_size in bytes

  uintx region_size = G1HeapRegionSize;

  if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {

    // We base the automatic calculation on the min heap size. This

    // can be problematic if the spread between min and max is quite

    // wide, imagine -Xms128m -Xmx32g. But, if we decided it based on

    // the max size, the region size might be way too large for the

    // min size. Either way, some users might have to set the region

    // size manually for some -Xms / -Xmx combos.

    // region的计算公式   min_heap_size就是 -Xms参数指定的值,如果没有指定默认为0
    region_size = MAX2(min_heap_size / TARGET_REGION_NUMBER,

                       (uintx) MIN_REGION_SIZE);

  }


  int region_size_log = log2_long((jlong) region_size);

  // Recalculate the region size to make sure it's a power of

  // 2. This means that region_size is the largest power of 2 that's

  // <= what we've calculated so far.

  region_size = ((uintx)1 << region_size_log);


  // Now make sure that we don't go over or under our limits.

  if (region_size < MIN_REGION_SIZE) {

    region_size = MIN_REGION_SIZE;

  } else if (region_size > MAX_REGION_SIZE) {

    region_size = MAX_REGION_SIZE;

  }


  // And recalculate the log.

  region_size_log = log2_long((jlong) region_size);

说白了就是-Xms /2048 ,如果这个值小于1,则取值为1,大于32则取值32;其它值则取与2,4,8,16相近的;

jdk1.8,以及jdk9中的实现:
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/gc_implementation/g1/heapRegion.cpp

// Minimum region size; we won't go lower than that.

// We might want to decrease this in the future, to deal with small

// heaps a bit more efficiently.

#define MIN_REGION_SIZE  (      1024 * 1024 )


// Maximum region size; we don't go higher than that. There's a good

// reason for having an upper bound. We don't want regions to get too

// large, otherwise cleanup's effectiveness would decrease as there

// will be fewer opportunities to find totally empty regions after

// marking.

#define MAX_REGION_SIZE  ( 32 * 1024 * 1024 )


// The automatic region size calculation will try to have around this

// many regions in the heap (based on the min heap size).

#define TARGET_REGION_NUMBER          2048


size_t HeapRegion::max_region_size() {

  return (size_t)MAX_REGION_SIZE;

}


void HeapRegion::setup_heap_region_size(size_t initial_heap_size, size_t max_heap_size) {

  uintx region_size = G1HeapRegionSize;

  if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
     //这里是代码的关键,(-Xms+-Xmx)/2/2048
    size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;

    region_size = MAX2(average_heap_size / TARGET_REGION_NUMBER,

                       (uintx) MIN_REGION_SIZE);

  }


  int region_size_log = log2_long((jlong) region_size);

  // Recalculate the region size to make sure it's a power of

  // 2. This means that region_size is the largest power of 2 that's

  // <= what we've calculated so far.

  region_size = ((uintx)1 << region_size_log);


  // Now make sure that we don't go over or under our limits.

  if (region_size < MIN_REGION_SIZE) {

    region_size = MIN_REGION_SIZE;

  } else if (region_size > MAX_REGION_SIZE) {

    region_size = MAX_REGION_SIZE;

  }


  // And recalculate the log.

  region_size_log = log2_long((jlong) region_size);


  // Now, set up the globals.

  guarantee(LogOfHRGrainBytes == 0, "we should only set it once");

  LogOfHRGrainBytes = region_size_log;


  guarantee(LogOfHRGrainWords == 0, "we should only set it once");

  LogOfHRGrainWords = LogOfHRGrainBytes - LogHeapWordSize;


  guarantee(GrainBytes == 0, "we should only set it once");

  // The cast to int is safe, given that we've bounded region_size by

  // MIN_REGION_SIZE and MAX_REGION_SIZE.

  GrainBytes = (size_t)region_size;


  guarantee(GrainWords == 0, "we should only set it once");

  GrainWords = GrainBytes >> LogHeapWordSize;

  guarantee((size_t) 1 << LogOfHRGrainWords == GrainWords, "sanity");


  guarantee(CardsPerRegion == 0, "we should only set it once");

  CardsPerRegion = GrainBytes >> CardTableModRefBS::card_shift;

}

关键代码在这两句:

  size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;

  region_size = MAX2(average_heap_size / TARGET_REGION_NUMBER,

                       (uintx) MIN_REGION_SIZE);

其实就是(-Xms+-Xmx)/2/2048 ,如果-Xms没有配置,那么就是0;

由此得出以下结论:

  1. region1.7计算方式与1.8,1.9是不同;
  2. region是在jvm启动的时候根据-Xms与-Xmx来确定的,它的范围在1M、2M、4M、8M、16M、32M;
  3. region的大小都是一样的,一经确定就不会改变,即使是humongous,只不过是多个连续的region区域;
  4. region数量并不是2048个,2048只是一个期望值,从计算方式可以看出来,除非我们将-Xms与-Xmx设置成一样大,并且大小必须大于2GB,小于64GB的情况下,这个值才能约等于2048,为什么是约等于?因为region大小必须是2的次幂,取值只能是1、2、4、8、16、32,如果不是正好等于这些值,会取一个近似的大小,如果内存很小2GB以下,region数量一定小于2048,如果内存很大64GB以上,则region数量会超过2048;

另外这里有个疑问,为什么要取2048?而不是其它值?期望大神能给我解答一下?

极大区域(Humongous regions)。这些区域被设计成保持标准区域大小的50%或者更大的对象。它们被保存在一个连续的区域集合里。最后,最后一个类型的区域就是堆空间里没有使用的区域

垃圾回收的区域有四种:
eden,survivor、old、Humongous 区域的回收;

使用G1垃圾回收方式有三种young、mixed、Full,young和mixed是G1回收器,Full是G1失败的情况下采用serial回收;
young会回收全部的eden和survivor区域;
mixed会回收全部的eden和survivor区域,同时会回收部分old 或Humongous区域;
Full gc则是G1回收失败的情况下,使用serial回收全部的区域,这时候我们会发现FullGc的次数会+1;

old和Humongous 回收都会跟随者GC pause (G1 Evacuation Pause) (mixed)

年轻带回收

2522.958: [GC pause (G1 Evacuation Pause) (young), 0.1063552 secs]
   [Parallel Time: 98.4 ms, GC Workers: 8]
      [GC Worker Start (ms): Min: 2522958.7, Avg: 2522958.8, Max: 2522958.9, Diff: 0.2]
      [Ext Root Scanning (ms): Min: 0.6, Avg: 0.9, Max: 2.0, Diff: 1.4, Sum: 7.1]
      [Update RS (ms): Min: 14.9, Avg: 16.4, Max: 16.9, Diff: 2.0, Sum: 131.3]
         [Processed Buffers: Min: 16, Avg: 28.1, Max: 71, Diff: 55, Sum: 225]
      [Scan RS (ms): Min: 32.6, Avg: 32.9, Max: 33.2, Diff: 0.6, Sum: 263.4]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [Object Copy (ms): Min: 47.7, Avg: 47.8, Max: 47.8, Diff: 0.1, Sum: 382.0]
      [Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.8]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.7]
      [GC Worker Total (ms): Min: 98.0, Avg: 98.2, Max: 98.3, Diff: 0.3, Sum: 785.4]
      [GC Worker End (ms): Min: 2523056.9, Avg: 2523057.0, Max: 2523057.1, Diff: 0.1]
   [Code Root Fixup: 0.1 ms]
   [Code Root Migration: 0.1 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.9 ms]
   [Other: 6.7 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.5 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 1.7 ms]
      [Free CSet: 3.5 ms]
   [Eden: 1524.0M(1524.0M)->0.0B(1508.0M) Survivors: 72.0M->80.0M Heap: 6957.7M(8192.0M)->5441.7M(8192.0M)]

会计算eden和survivor的大小被保存在清单统计信息中,用来辅助计算size,停顿时间目标之类的都会纳入考虑

老年代回收日志

//初始标记(stop the world事件)
//先执行一个常规的年轻代收集,然后标记那些可能有引用到年老代的对象的survivor区(g1中survivor区有很多,有引用到老年代对象的survivor区被称作根区,这是为了找老年代的gc root,jvm垃圾回收采用可达性分析算法,需要从gc root开始查找)
//还可能是: [GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0404763 secs]
155.623: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0720050 secs]
[Parallel Time: 67.9 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 155623.0, Avg: 155623.1, Max: 155623.2, Diff: 0.2]
[Ext Root Scanning (ms): Min: 0.4, Avg: 0.8, Max: 3.7, Diff: 3.3, Sum: 6.6]
[Code Root Marking (ms): Min: 0.0, Avg: 1.3, Max: 3.6, Diff: 3.6, Sum: 10.1]
[Update RS (ms): Min: 16.6, Avg: 18.7, Max: 19.8, Diff: 3.2, Sum: 149.7]
[Processed Buffers: Min: 17, Avg: 35.6, Max: 81, Diff: 64, Sum: 285]
[Scan RS (ms): Min: 22.5, Avg: 23.0, Max: 23.3, Diff: 0.8, Sum: 184.0]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.2, Diff: 0.2, Sum: 0.3]
[Object Copy (ms): Min: 23.6, Avg: 23.7, Max: 23.8, Diff: 0.2, Sum: 189.7]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.3]
[GC Worker Total (ms): Min: 67.5, Avg: 67.6, Max: 67.7, Diff: 0.2, Sum: 540.8]
[GC Worker End (ms): Min: 155690.7, Avg: 155690.7, Max: 155690.8, Diff: 0.1]
[Code Root Fixup: 0.2 ms]
[Code Root Migration: 0.5 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.3 ms]
[Other: 3.1 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.3 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 1.2 ms]
[Free CSet: 0.9 ms]
[Eden: 580.0M(580.0M)->0.0B(576.0M) Survivors: 48.0M->48.0M Heap: 1291.0M(1512.0M)->715.8M(1512.0M)]
[Times: user=0.56 sys=0.00, real=0.08 secs]

//根区扫描
//扫描上一阶段标记的根区(也就是有引用指向到老年代的survivor区),找到指向老年代的引用;这个发生在应用继续运行时。此阶段必须在下次年轻代收集执行前完成
155.695: [GC concurrent-root-region-scan-start]
155.737: [GC concurrent-root-region-scan-end, 0.0418092 secs]

//并发标记阶段
//遍历整个堆寻找活跃对象,这个发生在应用运行时,这个阶段可以被年轻代垃圾回收打断。
155.737: [GC concurrent-mark-start]
156.295: [GC concurrent-mark-end, 0.5581926 secs]

//重新标记(stop the world事件)
//完全标记堆中的活跃对象,使用一个叫作snapshot-at-the-beginning(SATB)的比CMS收集器的更快的算法
156.296: [GC remark 156.296: [GC ref-proc, 0.0031235 secs], 0.0065449 secs]
[Times: user=0.02 sys=0.01, real=0.00 secs]

//清理(stop the world事件)
//在存活对象和完全空闲的区域上执行统计(accounting)操作,擦写Remembered Sets.;
156.303: [GC cleanup 997M->995M(1512M), 0.0064480 secs]
[Times: user=0.05 sys=0.00, real=0.01 secs]

//并发清理
//重置空heap区并将它们返还给空闲列表(free list);
156.310: [GC concurrent-cleanup-start]
156.310: [GC concurrent-cleanup-end, 0.0000178 secs]

//(*)复制(stop the world事件)
//一般都是紧跟着一个young 复制,外加n个mixed复制操作
//这些是stop the world暂停为了疏散或者复制活跃对象到新的未使用的区域。这个可以由被记录为[GC Pause (young)]的年轻代区域或者被记录为[GC Pause (mixed)]年轻代和年老代区域完成
157.032: [GC pause (G1 Evacuation Pause) (young), 0.0661416 secs]
[Parallel Time: 62.2 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 157032.1, Avg: 157032.1, Max: 157032.2, Diff: 0.1]
[Ext Root Scanning (ms): Min: 0.5, Avg: 0.7, Max: 1.8, Diff: 1.3, Sum: 5.9]
[Update RS (ms): Min: 17.1, Avg: 18.4, Max: 18.9, Diff: 1.8, Sum: 146.8]
[Processed Buffers: Min: 22, Avg: 36.8, Max: 51, Diff: 29, Sum: 294]
[Scan RS (ms): Min: 21.3, Avg: 21.7, Max: 21.8, Diff: 0.6, Sum: 173.7]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.2]
[Object Copy (ms): Min: 21.0, Avg: 21.0, Max: 21.1, Diff: 0.1, Sum: 168.2]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.3]
[GC Worker Total (ms): Min: 61.8, Avg: 61.9, Max: 62.0, Diff: 0.1, Sum: 495.2]
[GC Worker End (ms): Min: 157094.0, Avg: 157094.0, Max: 157094.1, Diff: 0.1]
[Code Root Fixup: 0.2 ms]
[Code Root Migration: 0.6 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.3 ms]
[Other: 2.8 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.3 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 1.1 ms]
[Free CSet: 0.9 ms]
[Eden: 576.0M(576.0M)->0.0B(28.0M) Survivors: 48.0M->46.0M Heap: 1289.8M(1512.0M)->716.1M(1512.0M)]
[Times: user=0.51 sys=0.00, real=0.07 secs]
157.126: [GC pause (G1 Evacuation Pause) (mixed), 0.1268152 secs]
[Parallel Time: 117.4 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 157127.7, Avg: 157127.8, Max: 157127.9, Diff: 0.1]
[Ext Root Scanning (ms): Min: 0.6, Avg: 0.8, Max: 2.0, Diff: 1.5, Sum: 6.5]
[Update RS (ms): Min: 31.5, Avg: 32.9, Max: 33.1, Diff: 1.6, Sum: 263.0]
[Processed Buffers: Min: 43, Avg: 64.5, Max: 83, Diff: 40, Sum: 516]
[Scan RS (ms): Min: 34.5, Avg: 34.8, Max: 35.0, Diff: 0.4, Sum: 278.5]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.1, Max: 0.4, Diff: 0.4, Sum: 0.8]
[Object Copy (ms): Min: 48.3, Avg: 48.4, Max: 48.5, Diff: 0.3, Sum: 387.0]
[Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 1.0]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
[GC Worker Total (ms): Min: 117.1, Avg: 117.1, Max: 117.2, Diff: 0.1, Sum: 936.9]
[GC Worker End (ms): Min: 157244.9, Avg: 157244.9, Max: 157244.9, Diff: 0.0]
[Code Root Fixup: 0.7 ms]
[Code Root Migration: 2.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.3 ms]
[Other: 6.4 ms]
[Choose CSet: 1.2 ms]
[Ref Proc: 0.2 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 2.5 ms]
[Free CSet: 2.0 ms]
[Eden: 28.0M(28.0M)->0.0B(66.0M) Survivors: 46.0M->8192.0K Heap: 744.1M(1512.0M)->607.7M(1512.0M)]
[Times: user=0.96 sys=0.00, real=0.12 secs]
157.315: [GC pause (G1 Evacuation Pause) (mixed), 0.1369814 secs]
[Parallel Time: 131.4 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 157315.8, Avg: 157315.8, Max: 157315.9, Diff: 0.1]
[Ext Root Scanning (ms): Min: 0.5, Avg: 0.8, Max: 2.2, Diff: 1.7, Sum: 6.2]
[Update RS (ms): Min: 83.5, Avg: 85.2, Max: 85.7, Diff: 2.1, Sum: 681.9]
[Processed Buffers: Min: 112, Avg: 135.2, Max: 155, Diff: 43, Sum: 1082]
[Scan RS (ms): Min: 26.1, Avg: 26.4, Max: 26.6, Diff: 0.4, Sum: 211.3]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.2, Diff: 0.2, Sum: 0.4]
[Object Copy (ms): Min: 18.3, Avg: 18.5, Max: 18.6, Diff: 0.4, Sum: 147.9]
[Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.8]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
[GC Worker Total (ms): Min: 131.0, Avg: 131.1, Max: 131.1, Diff: 0.1, Sum: 1048.6]
[GC Worker End (ms): Min: 157446.9, Avg: 157446.9, Max: 157446.9, Diff: 0.0]
[Code Root Fixup: 0.4 ms]
[Code Root Migration: 1.2 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.3 ms]
[Other: 3.7 ms]
[Choose CSet: 0.7 ms]
[Ref Proc: 0.3 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 1.2 ms]
[Free CSet: 1.1 ms]
[Eden: 66.0M(66.0M)->0.0B(752.0M) Survivors: 8192.0K->10.0M Heap: 673.7M(1512.0M)->579.6M(1512.0M)]
[Times: user=1.05 sys=0.00, real=0.13 secs]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值