君子以自强不息。
分区
分区(Heap Region,HR)或称堆分区,是 G1 堆和操作系统交互的最小管理单位。G1 的分区类型(HeapRegionType)大致可以分为四类:
- 自由分区(Free Heap Region,FHR)
- 新生代分区(Young Heap Region,YHR)
- 大对象分区(Humongous Heap Region,HHR)
- 老生代分区(Old Heap Region,OHR)
其中新生代分区又可以分为“Eden”和“Survivor”;大对象分区又可以分为“大对象头分区”和“大对象连续分区”。
HR 的大小直接影响分配和垃圾回收效率。如果过大,一个 HR 可以存放多个对象,分配效率高,但是回收的时候花费时间过长;如果太小则导致分配效率低下。HR大小可由以下方式确定:
- 可以通过参数 G1HeapRegionSize 来指定大小,这个参数的默认值为0。
- 启发式推断,即在不指定HR大小的时候,由 G1 启发式地推断 HR 大小。
新生代大小
新生代大小指的是新生代内存空间的大小,G1 中增加了两个参数 G1MaxNewSizePercent 和 G1NewSizePercent 用于控制新生代的大小,整体逻辑如下:
- 如果设置新生代最大值(MaxNewSize)和最小值(NewSize),可以根据这些值计算新生代包含的最大的分区和最小的分区;注意 Xmn 等价于设置了 MaxNewSize 和 NewSize,且 NewSize=MaxNewSize。
- 如果既设置了最大值或者最小值,又设置了 NewRatio,则忽略 NewRatio。
- 如果没有设置新生代最大值和最小值,但是设置了 NewRatio,则新生代的最大值和最小值是相同的,都是整个堆空间/(NewRatio+1)。
如果 G1 推断出最大值和最小值相等,则说明新生代不会动态变化。不会动态变化意味着 G1 在后续对新生代垃圾回收的时候可能不能满足期望停顿的时间。
如果 G1 是启发式推断新生代的大小。使用一个分区列表,扩张时如果有空闲的分区列表则可以直接把空闲分区加入到新生代分区列表中,如果没有的话则分配新的分区然后把它加入到新生代分区列表中。G1 有一个线程专门抽样处理预测新生代列表的长度应该多大,并动态调整。
分配新分区时,何时扩展?一次扩展多少内存?
G1 是自适应扩展内存空间的。参数 -XX:GCTimeRatio 表示 GC 与应用的耗费时间比,G1 中默认为9,计算方式为:
1 |
|
即 G1 GC 时间与应用时间占比不超过10%时不需要动态扩展,当 GC 时间超过这个阈值的10%,可以动态扩展。扩展时有一个参数 G1ExpandByPercentOfAvailable(默认值是20)来控制一次扩展的比例,即每次都至少从未提交的内存中申请20%,有下限要求(一次申请的内存不能少于1M,最多是当前已分配的一倍)。