JVM虚拟机——G1垃圾收集器分区Region

G1之前的垃圾收集器都会将堆分成三个部分,新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation),根据不同的分区类型,采用不同的策略进行回收。

G1仍然保留新生代和老年代的概念,但新生代和老年代不再是固定的了,它们都是一系列区域(不需要连续)的动态集合。G1把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以作为新生代的Eden空间、Survivor空间,或者老年代空间。G1堆和操作系统交互的最小管理单位称为分区(Heap Region,HR)或称堆分区。

G1的分区类型(HeapRegionType)大致可以分为四类:

  • 自由分区(Free Heap Region,FHR)

  • 新生代分区(Young Heap Region,YHR)

  • 大对象分区(Humongous Heap Region,HHR)

  • 老生代分区(Old Heap Region,OHR)

其中新生代分区又可以分为Eden和Survivor;大对象分区又可以分为:大对象头分区和大对象连续分区。

Humongous Heap Region专门用来存储大对象,只要大小超过了一个Region容量一半的对象即可判定为大对象。Region的大小可以通过参数-XX:G1HeapRegionSize设定,取值范围为1MB~32MB,且应为2的N次幂,默认值为0。

超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待。

在G1中每个分区的大小都是相同的,HR的大小直接影响分配和垃圾回收效率。如果过大,一个HR可以存放多个对象,分配效率高,但是回收的时候花费时间过长;如果太小则导致分配效率低下。为了达到分配效率和清理效率的平衡,HR有一个上限值和下限值,目前上限是32MB,下限是1MB(HR的大小只能为1MB、2MB、4MB、8MB、16MB和32MB),默认情况下,整个堆空间分为2048个HR(该值可以自动根据最小的堆分区大小计算得出)。

HR大小可由以下方式确定:

1、可以通过参数G1HeapRegionSize来指定大小,这个参数的默认值为0。

[root@jeespring ~]# java -XX:+PrintFlagsFinal -version | grep G1HeapRegionSize
   size_t G1HeapRegionSize          = 0             {product} {default}
java version "11.0.8" 2020-07-14 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.8+10-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.8+10-LTS, mixed mode)

2、启发式推断,即在不指定HR大小的时候,由G1启发式地推断HR大小。

HR启发式推断根据堆空间的最大值和最小值以及HR个数进行推断,设置InitialHeapSize(默认为0)等价于设置Xms,设置MaxHeapSize(默认为96MB)等价于设置Xmx。

[root@jeespring ~]# java -XX:+PrintCommandLineFlags -version
-XX:G1ConcRefinementThreads=4 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=132500800 
-XX:MaxHeapSize=2120012800 -XX:+PrintCommandLineFlags -XX:ReservedCodeCacheSize=251658240 
-XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops 
-XX:+UseG1GC -XX:-UseLargePagesIndividualAllocation
java version "11.0.8" 2020-07-14 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.8+10-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.8+10-LTS, mixed mode)

堆分区默认大小的计算方式在HeapRegion.cpp中的setup_heap_region_size(),代码如下所示:

默认region_size 为 1M,最大为32M,HR个数为2048个

openjdk-jdk11u/src/hotspot/share/gc/g1/heapRegionBounds.hpp

openjdk-jdk11u/src/hotspot/share/gc/g1/HeapRegion.cpp

按照默认值计算,G1可以管理的最大内存为2048×32MB=64GB。假设设置xms=32G,xmx=128G,则每个堆分区的大小为32M,分区个数动态变化范围从1024到4096个。

region_size计算过程

  size_t region_size = G1HeapRegionSize;
  if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
    size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;
    region_size = MAX2(average_heap_size / HeapRegionBounds::target_number(),
                       HeapRegionBounds::min_size());
  }
  int region_size_log = log2_long((jlong) region_size);
  region_size = ((size_t)1 << region_size_log);
  if (region_size < HeapRegionBounds::min_size()) {
    region_size = HeapRegionBounds::min_size();
  } else if (region_size > HeapRegionBounds::max_size()) {
    region_size = HeapRegionBounds::max_size();
  }

1、没有配置G1HeapRegionSize

我们线上配置的JVM参数-Xmx4096m 和 -Xms4096m,根据配置计算过程如下:

average_heap_size=(4096m+4096m)/2=4096m

region_size=MAX2(4096m/2048, 1m)=2m

region_size_log=21(log2_long函数是获取以2为底,region_size的对数,2^21=2*1024*1024<=2m)

region_size=2^21=2m(region_size_log左移1位,也就是2^21)

region_size=2m(MIN_REGION_SIZE(1m)<= 2m <=MAX_REGION_SIZE(32m))

2、配置G1HeapRegionSize大小

JVM参数配置:-Xmx4096m 、-Xms4096m 、-XX:G1HeapRegionSize=8m,由于配置了G1HeapRegionSize的大小,FLAG_IS_DEFAULT(G1HeapRegionSize)条件为false,计算过程如下:

region_size=8m

region_size_log=22(2^23=2^3*1024*1024<=8m)

region_size=2^23=8m(region_size_log左移1位,也就是2^23)

region_size=8m(MIN_REGION_SIZE(1m)<= 8m <=MAX_REGION_SIZE(32m))


源码下载地址:

https://codeload.github.com/AdoptOpenJDK/openjdk-jdk11u

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JVM是一种虚拟机Java Virtual Machine),能够在不同操作系统和硬件平台上运行Java程序。而G1垃圾收集器JVM中的一种垃圾收集算法,可以处理大型Java堆。 使用G1垃圾收集器能够提高应用程序性能,因为它采用分区技术和优先级调度算法,可以根据应用程序的使用情况,动态地分配堆空间分区,从而减少垃圾收集时间和暂停时间。 下面是使用G1垃圾收集器来优化JVM的步骤: 第一步,设置JVM参数,例如开启G1垃圾收集器,设置堆空间大小等。 第二步,使用JVisualVM或其他工具,对应用程序进行分析,确定是否存在内存泄漏或内存过度消耗的现象。如果有问题,则需要对应用程序进行修改,以降低内存使用率。 第三步,对应用程序进行压测,确定最大并发并适当调整G1垃圾收集器参数,例如设置初始停顿时间、最大停顿时间、空闲时间等。 但需要注意的是,使用G1垃圾收集器时需要事先评估应用程序的运行环境和特性,例如硬件配置、每秒请求计数、响应时间等。只有在合适的环境下,G1垃圾收集器才能发挥最佳效果。同时,应用程序也需要符合一些条件,例如堆空间不能太小,内存消耗不能太大等。 总之,通过优化JVM,使用G1垃圾收集器能够提高Java应用程序的性能和可靠性,减少停顿时间。但使用时需要仔细评估和测试,确保最佳效果。 ### 回答2: JVMJava虚拟机的缩写,是Java运行环境的核心部分。垃圾收集器JVM的一个重要组成部分,负责回收程序的无用对象和内存。G1垃圾收集器JVM中的一种,是目前比较流行的一种。下面介绍G1垃圾收集器的优化使用方法。 首先,G1垃圾收集器最大的优点是能够充分利用多核处理器和大内存的优势。因此,在使用G1垃圾收集器时,需要配置合适的垃圾回收线程数和堆内存大小。通常情况下,推荐将垃圾回收线程数设置为CPU核心数的一半左右,而堆内存大小则应根据应用程序的实际情况设定。 其次,G1垃圾收集器还支持增量垃圾回收和并发标记。这意味着垃圾收集器可以在应用程序执行的同时,进行部分的垃圾回收和标记操作。这有利于减少垃圾回收对应用程序执行的影响。 再次,G1垃圾收集器还支持混合模式。这种模式下,垃圾收集器会将堆内存分为多个区域,并按照各个区域的使用情况决定垃圾回收的策略。一些非常重要的区域可以在短时间内进行Full GC,而其它区域则可以使用增量式垃圾回收策略。这一功能可以进一步提高垃圾回收的效率。 最后,在使用G1垃圾收集器时,还需要注意一些细节问题。例如,需要选择合适的回收阈值、合理配置回收周期等等。此外,一些调试工具如JConsole、JVisualVM等也可以帮助开发者监控和调整G1垃圾收集器的性能。 总之,G1垃圾收集器是目前JVM中性能较优异的垃圾收集器之一。在使用G1垃圾收集器时,需要根据实际情况合理配置线程数、堆内存大小和一些参数,同时关注混合模式、增量垃圾回收和并发标记等特点,才能充分发挥其性能优势。 ### 回答3: JVMJava虚拟机的缩写,它是Java程序运行的环境,它提供了一个平台无关的执行环境,能够提高Java应用程序的效率和安全性。Java应用程序的性能优化是一个复杂的过程,其中之一的重要方面是垃圾收集器的优化。 G1JVM中的一种垃圾收集器,它主要用于大堆内存应用程序,它在处理垃圾回收时可以实现高吞吐量和低延迟,而且它可以管理大容量的内存,能够处理高并发情况下的大量垃圾回收。 G1垃圾收集器具有以下优点: 1.低延迟:G1垃圾收集器能够有效地降低应用程序的延迟,因为它是一个分区式的垃圾收集器,它会将内存分成多个区域,每个区域都有自己的垃圾回收时间,这样可以最大程度的减少垃圾回收的时间。 2.高吞吐量:G1垃圾收集器能够管理大容量的内存,能够处理大量的垃圾回收,因此它的吞吐量很高。 3.可预测性:G1垃圾收集器能够实现可预测性垃圾回收,这意味着它可以为每个应用程序分配一个确定的垃圾回收时间,从而避免出现系统性能波动的情况。 4.自适应:G1垃圾收集器能够根据内存的使用情况来自动调整垃圾回收的策略,从而最大程度地优化垃圾回收的效率和性能。 在使用G1垃圾收集器时,需要注意以下几点: 1.适当配置参数:需要根据应用程序的实际情况,适当配置G1的参数,以提高垃圾回收的效率和性能。 2.避免频繁Full GC:G1垃圾收集器能够尽量避免Full GC,但是在一些场景下,还是会出现Full GC的情况,因此需要尽量避免频繁Full GC的情况出现。 3.避免内存泄漏:G1垃圾收集器虽然能够处理大量垃圾,但是它无法处理内存泄漏的情况,因此需要及时发现和解决内存泄漏的问题。 总之,G1垃圾收集器是一个高性能、高效率的垃圾回收器,能够满足大堆内存应用程序的垃圾回收需求。在使用过程中,需要根据实际情况适当配置参数,避免频繁Full GC和内存泄漏的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值