Learn about how to adapt and tune the G1 GC for evaluation, analysis and performance.
The Garbage First Garbage Collector (G1 GC) is the low-pause, server-style generational garbage collector for Java HotSpot VM. The G1 GC uses concurrent and parallel phases to achieve its target pause time and to maintain good throughput. When G1 GC determines that a garbage collection is necessary, it collects the regions with the least live data first (garbage first).
A garbage collector (GC) is a memory management tool. The G1 GC achieves automatic memory management through the following operations:
Allocating objects to a young generation and promoting aged objects into an old generation.
Finding live objects in the old generation through a concurrent (parallel) marking phase. The Java HotSpot VM triggers the marking phase when the total Java heap occupancy exceeds the default threshold.
Recovering free memory by compacting live objects through parallel copying.
Here, we look at how to adapt and tune the G1 GC for evaluation, analysis and performance—we assume a basic understanding of Java garbage collection.
The G1 GC is a regionalized and generational garbage collector, which means that the Java object heap (heap) is divided into a number of equally sized regions. Upon startup, the Java Virtual Machine (JVM) sets the region size. The region sizes can vary from 1 MB to 32 MB depending on the heap size. The goal is to have no more than 2048 regions. The eden, survivor, and old generations are logical sets of these regions and are not contiguous.
The G1 GC has a pause time-target that it tries to meet (soft real time). During young collections, the G1 GC adjusts its young generation (eden and survivor sizes) to meet the soft real-time target. During mixed collections, the G1 GC adjusts the number of old regions that are collected based on a target number of mixed garbage collections, the percentage of live objects in each region of the heap, and the overall acceptable heap waste percentage.
The G1 GC reduces heap fragmentation by incremental parallel copying of live objects from one or more sets of regions (called Collection Set (CSet)) into different new region(s) to achieve compaction. The goal is to reclaim as much heap space as possible, starting with those regions that contain the most reclaimable space, while attempting to not exceed the pause time goal (garbage first).
The G1 GC uses independent Remembered Sets (RSets) to track references into regions. Independent RSets enable parallel and independent collection of regions because only a region's RSet must be scanned for references into that region, instead of the whole heap. The G1 GC uses a post-write barrier to record changes to the heap and update the RSets.
Apart from evacuation pauses (described below) that compose the stop-the-world (STW) young and mixed garbage collections, the G1 GC also has parallel, concurrent, and multiphase marking cycles. G1 GC uses the Snapshot-At-The-Beginning (SATB) algorithm, which takes a snapshot of the set of live objects in the heap at the start of a marking cycle. The set of live objects is composed of the live objects in the snapshot, and the objects allocated since the start of the marking cycle. The G1 GC marking algorithm uses a pre-write barrier to record and mark objects that are part of the logical snapshot.
The G1 GC satisfies most allocation requests from regions added to the eden set of regions. During a young garbage collection, the G1 GC collects both the eden regions and the survivor regions from the previous garbage collection. The live objects from the eden and survivor regions are copied, or evacuated, to a new set of regions. The destination region for a particular object depends upon the object's age; an object that has aged sufficiently evacuates to an old generation region (that is, promoted); otherwise, the object evacuates to a survivor region and will be included in the CSet of the next young or mixed garbage collection.
Upon successful completion of a concurrent marking cycle, the G1 GC switches from performing young garbage collections to performing mixed garbage collections. In a mixed garbage collection, the G1 GC optionally adds some old regions to the set of eden and survivor regions that will be collected. The exact number of old regions added is controlled by a number of flags that will be discussed later (see "Taming Mixed GCs"). After the G1 GC collects a sufficient number of old regions (over multiple mixed garbage collections), G1 reverts to performing young garbage collections until the next marking cycle completes.
The marking cycle has the following phases:
Initial mark phase: The G1 GC marks the roots during this phase. This phase is piggybacked on a normal (STW) young garbage collection.
Root region scanning phase: The G1 GC scans survivor regions of the initial mark for references to the old generation and marks the referenced objects. This phase runs concurrently with the application (not STW) and must complete before the next STW young garbage collection can start.
Concurrent marking phase: The G1 GC finds reachable (live) objects across the entire heap. This phase happens concurrently with the application, and can be interrupted by STW young garbage collections.
Remark phase: This phase is STW collection and helps the completion of the marking cycle. G1 GC drains SATB buffers, traces unvisited live objects, and performs reference processing.
Cleanup phase: In this final phase, the G1 GC performs the STW operations of accounting and RSet scrubbing. During accounting, the G1 GC identifies completely free regions and mixed garbage collection candidates. The cleanup phase is partly concurrent when it resets and returns the empty regions to the free list.
The G1 GC is an adaptive garbage collector with defaults that enable it to work efficiently without modification. Here is a list of important options and their default values. This list applies to the latest Java HotSpot VM, build 24. You can adapt and tune the G1 GC to your application performance needs by entering the following options with changed settings on the JVM command line.
-XX:G1HeapRegionSize=n
Sets the size of a G1 region. The value will be a power of two and can range from 1MB to 32MB. The goal is to have around 2048 regions based on the minimum Java heap size.
-XX:MaxGCPauseMillis=200
Sets a target value for desired maximum pause time. The default value is 200 milliseconds. The specified value does not adapt to your heap size.
-XX:G1NewSizePercent=5
Sets the percentage of the heap to use as the minimum for the young generation size. The default value is 5 percent of your Java heap. This is an experimental flag. See "How to unlock experimental VM flags" for an example. This setting replaces the -XX:DefaultMinNewGenPercent
setting. This setting is not available in Java HotSpot VM, build 23.
-XX:G1MaxNewSizePercent=60
Sets the percentage of the heap size to use as the maximum for young generation size. The default value is 60 percent of your Java heap. This is an experimental flag. See "How to unlock experimental VM flags" for an example. This setting replaces the -XX:DefaultMaxNewGenPercent
setting. This setting is not available in Java HotSpot VM, build 23.
-XX:ParallelGCThreads=n
Sets the value of the STW worker threads. Sets the value of n to the number of logical processors. The value of n
is the same as the number of logical processors up to a value of 8.
If there are more than eight logical processors, sets the value of n
to approximately 5/8 of the logical processors. This works in most cases except for larger SPARC systems where the value of n
can be approximately 5/16 of the logical processors.
-XX:ConcGCThreads=n
Sets the number of parallel marking threads. Sets n
to approximately 1/4 of the number of parallel garbage collection threads (ParallelGCThreads
).
-XX:InitiatingHeapOccupancyPercent=45
Sets the Java heap occupancy threshold that triggers a marking cycle. The default occupancy is 45 percent of the entire Java heap.
-XX:G1MixedGCLiveThresholdPercent=65
Sets the occupancy threshold for an old region to be included in a mixed garbage collection cycle. The default occupancy is 65 percent. This is an experimental flag. See "How to unlock experimental VM flags" for an example. This setting replaces the -XX:G1OldCSetRegionLiveThresholdPercent
setting. This setting is not available in Java HotSpot VM, build 23.
-XX:G1HeapWastePercent=10
Sets the percentage of heap that you are willing to waste. The Java HotSpot VM does not initiate the mixed garbage collection cycle when the reclaimable percentage is less than the heap waste percentage. The default is 10 percent. This setting is not available in Java HotSpot VM, build 23.
-XX:G1MixedGCCountTarget=8
Sets the target number of mixed garbage collections after a marking cycle to collect old regions with at most G1MixedGCLIveThresholdPercent
live data. The default is 8 mixed garbage collections. The goal for mixed collections is to be within this target number. This setting is not available in Java HotSpot VM, build 23.
-XX:G1OldCSetRegionThresholdPercent=10
Sets an upper limit on the number of old regions to be collected during a mixed garbage collection cycle. The default is 10 percent of the Java heap. This setting is not available in Java HotSpot VM, build 23.
-XX:G1ReservePercent=10
Sets the percentage of reserve memory to keep free so as to reduce the risk of to-space overflows. The default is 10 percent. When you increase or decrease the percentage, make sure to adjust the total Java heap by the same amount. This setting is not available in Java HotSpot VM, build 23.
To change the value of experimental flags, you must unlock them first. You can do this by setting -XX:+UnlockExperimentalVMOptions
explicitly on the command line before any experimental flags. For example:
> java -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=10 -XX:G1MaxNewSizePercent=75 G1test.jar
When you evaluate and fine-tune G1 GC, keep the following recommendations in mind:
Young Generation Size: Avoid explicitly setting young generation size with the -Xmn
option or any or other related option such as -XX:NewRatio
. Fixing the size of the young generation overrides the target pause-time goal.
Pause Time Goals: When you evaluate or tune any garbage collection, there is always a latency versus throughput trade-off. The G1 GC is an incremental garbage collector with uniform pauses, but also more overhead on the application threads. The throughput goal for the G1 GC is 90 percent application time and 10 percent garbage collection time. When you compare this to Java HotSpot VM's throughput collector, the goal there is 99 percent application time and 1 percent garbage collection time. Therefore, when you evaluate the G1 GC for throughput, relax your pause-time target. Setting too aggressive a goal indicates that you are willing to bear an increase in garbage collection overhead, which has a direct impact on throughput. When you evaluate the G1 GC for latency, you set your desired (soft) real-time goal, and the G1 GC will try to meet it. As a side effect, throughput may suffer.
Taming Mixed Garbage Collections: Experiment with the following options when you tune mixed garbage collections. See "Important Defaults" for information about these options:
-XX:InitiatingHeapOccupancyPercent
For changing the marking threshold.
-XX:G1MixedGCLiveThresholdPercent
and -XX:G1HeapWastePercent
When you want to change the mixed garbage collections decisions.
-XX:G1MixedGCCountTarget
and -XX:G1OldCSetRegionThresholdPercent
When you want to adjust the CSet for old regions.
When you see to-space overflow/exhausted messages in your logs, the G1 GC does not have enough memory for either survivor or promoted objects, or for both. The Java heap cannot expand since it is already at its max. Example messages:
924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space exhausted), 0.1957310 secs]
OR924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space overflow), 0.1957310 secs]
To alleviate the problem, try the following adjustments:
Increase the value of the -XX:G1ReservePercent
option (and the total heap accordingly) to increase the amount of reserve memory for "to-space".
Start the marking cycle earlier by reducing the -XX:InitiatingHeapOccupancyPercent
.
You can also increase the value of the -XX:ConcGCThreads
option to increase the number of parallel marking threads.
See "Important Defaults" for a description of these options.
For G1 GC, any object that is more than half a region size is considered a "Humongous object". Such an object is allocated directly in the old generation into "Humongous regions". These Humongous regions are a contiguous set of regions. StartsHumongous
marks the start of the contiguous set and ContinuesHumongous
marks the continuation of the set.
Before allocating any Humongous region, the marking threshold is checked, initiating a concurrent cycle, if necessary.
Dead Humongous objects are freed at the end of the marking cycle during the cleanup phase also during a full garbage collection cycle.
In-order to reduce copying overhead, the Humongous objects are not included in any evacuation pause. A full garbage collection cycle compacts Humongous objects in place.
Since each individual set of StartsHumongous and ContinuesHumongous regions contains just one humongous object, the space between the end of the humongous object and the end of the last region spanned by the object is unused. For objects that are just slightly larger than a multiple of the heap region size, this unused space can cause the heap to become fragmented.
If you see back-to-back concurrent cycles initiated due to Humongous allocations and if such allocations are fragmenting your old generation, please increase your -XX:G1HeapRegionSize
such that previous Humongous objects are no longer Humongous and will follow the regular allocation path.
G1 GC is a regionalized, parallel-concurrent, incremental garbage collector that provides more predictable pauses compared to other HotSpot GCs. The incremental nature lets G1 GC work with larger heaps and still provide reasonable worst-case response times. The adaptive nature of G1 GC just needs a maximum soft-real time pause-time goal along-with the desired maximum and minimum size for the Java heap on the JVM command line.
translation:
了解如何调整和调整G1 GC用于评估,分析和性能。
该垃圾首先垃圾收集器(GC G1)是Java HotSpot虚拟机的低暂停,服务器风格的分代垃圾收集器。G1 GC使用并行和并行阶段来实现其目标暂停时间并保持良好的吞吐量。G1 GC确定需要进行垃圾回收时,首先收集实时数据量最少的区域(垃圾优先)。
垃圾收集器(GC)是一种内存管理工具。G1 GC通过以下操作实现自动内存管理:
将物品分配给年轻一代,并将老年物品推向老一代。
通过并行(并行)标记阶段在老一代中查找活物。当Java堆占用率超过默认阈值时,Java HotSpot VM会触发标记阶段。
通过并行复制压缩活动对象来恢复空闲内存。
在这里,我们看看如何调整和调整G1 GC以进行评估,分析和性能 - 我们假定对Java垃圾收集有一个基本的了解。
G1 GC是一个区域化和世代的垃圾收集器,这意味着Java对象堆(堆)被分成许多相同大小的区域。启动时,Java虚拟机(JVM)设置区域大小。区域大小可以从1 MB到32 MB不等,具体取决于堆大小。目标是不超过2048个地区。伊甸园,幸存者和老一代是这些地区的逻辑集合,不是连续的。
G1 GC有一个暂停时间目标,它试图满足(软实时)。在年轻的收集,G1 GC调整其年轻一代(伊甸园和幸存者的大小),以满足软实时目标。在混合采集期间,G1 GC根据混合垃圾收集的目标数量,堆中每个区域的活动对象的百分比以及整体可接受的堆垃圾百分比来调整收集的旧区域的数量。
G1 GC通过将活动对象从一个或多个区域(称为集合集(CSet))增量并行复制到不同的新区域来减少堆碎片,从而实现压缩。目标是尽可能回收堆空间,从包含最多可回收空间的区域开始,同时尝试不超过暂停时间目标(垃圾优先)。
G1 GC使用独立的记忆集(RSets)来跟踪对区域的引用。独立的RSets可以并行和独立地收集区域,因为只有一个区域的RSet必须被扫描以引用到该区域,而不是整个堆。G1 GC使用写后屏障来记录对堆的更改并更新RSets。
除了组成停止世界(STW)年轻和混合垃圾收集的疏散暂停(下面描述)之外,G1 GC还具有并行,并发和多相标记循环。G1 GC使用快速入门(SATB)算法,该算法在标记周期开始时在堆中生成一组活动对象的快照。活动对象集由快照中的活动对象以及自标记周期开始以来分配的对象组成。G1 GC标记算法使用预写屏障来记录和标记属于逻辑快照一部分的对象。
G1 GC满足来自添加到伊甸园区域的区域的大部分分配请求。在一个年轻的垃圾回收过程中,G1 GC从前一次的垃圾收集中收集伊甸园地区和幸存者地区。来自伊甸园和幸存者地区的活体被复制或撤离到一组新的地区。特定对象的目的地区域取决于对象的年龄; 一个已经老龄化的物体已经足够撤离到老一代的地区(即被推广); 否则,对象撤离到一个幸存者地区,并将被包括在下一个年轻人或混合垃圾收集的CSet中。
成功完成并发标记循环后,G1 GC将从执行年轻的垃圾收集切换到执行混合垃圾收集。在混合垃圾收集中,G1 GC可选地将一些旧区域添加到将被收集的伊甸园和幸存区域集合中。所添加的旧地区的确切数量由稍后讨论的多个标记控制(请参阅“ 驯服混合GC ”)。在G1 GC收集足够数量的旧区域(在多个混合垃圾收集之上)之后,G1将恢复执行年轻垃圾收集,直到下一个标记周期完成。
标记周期有以下几个阶段:
初始标记阶段:G1 GC在此阶段标记根。这个阶段是在一个正常的(STW)年轻垃圾收集上搭载的。
根区扫描阶段:G1 GC扫描初始标记的生存区域,以便参考老一代并标记参考物体。这个阶段与应用程序同时运行(不是STW),并且必须在下一个STW年轻垃圾回收开始之前完成。
并行标记阶段:G1 GC在整个堆中找到可访问(活动)的对象。这个阶段与应用程序同时发生,可以被STW年轻垃圾收集中断。
备注阶段:这个阶段是STW收集,并帮助完成标记周期。G1 GC消耗SATB缓冲区,跟踪未访问的活动对象,并执行参考处理。
清理阶段:在这个最后阶段,G1 GC执行会计和RSet清理的STW操作。在会计期间,G1 GC确定完全空闲区域和混合垃圾收集候选人。清理阶段在重置并将空白区域返回到空闲列表时是部分并发的。
G1 GC是一个自适应垃圾回收器,具有默认设置,使其无需修改即可高效工作。以下是重要选项及其默认值的列表。此列表适用于最新的Java HotSpot VM版本24.您可以通过在JVM命令行上输入以下选项并更改设置,来调整和调整G1 GC以满足您的应用程序性能需求。
-XX:G1HeapRegionSize =正
设置G1区域的大小。该值将是2的幂,可以从1MB到32MB。目标是基于最小的Java堆大小,大约有2048个区域。
-XX:MaxGCPauseMillis = 200
为所需的最大暂停时间设置一个目标值。默认值是200毫秒。指定的值不适应您的堆大小。
-XX:G1NewSizePercent = 5
设置堆的百分比作为年轻一代规模的最小值。默认值是Java堆的5%。这是一个实验性的标志。有关示例,请参阅“ 如何解锁实验性VM标志 ”。此设置取代-XX:DefaultMinNewGenPercent
设置。此设置在Java HotSpot VM(版本23)中不可用。
-XX:G1MaxNewSizePercent = 60
设置用于年轻一代大小的最大堆大小的百分比。默认值是Java堆的60%。这是一个实验性的标志。有关示例,请参阅“ 如何解锁实验性VM标志 ”。此设置取代-XX:DefaultMaxNewGenPercent
设置。此设置在Java HotSpot VM(版本23)中不可用。
-XX:ParallelGCThreads =正
设置STW工作线程的值。将n的值设置为逻辑处理器的数量。该值与n
逻辑处理器的数量相同,最大值为8。
如果有八个以上的逻辑处理器,则将逻辑处理器的值设置n
为大约5/8。这在大多数情况下工作,除了较大的SPARC系统,其值n
可以是逻辑处理器的大约5/16。
-XX:ConcGCThreads =正
设置平行标记线程的数量。设置n
为并行垃圾回收线程数(ParallelGCThreads
)的大约1/4 。
-XX:InitiatingHeapOccupancyPercent = 45
设置触发标记周期的Java堆占用阈值。默认占用率是整个Java堆的45%。
-XX:G1MixedGCLiveThresholdPercent = 65
将旧区域的占用阈值设置为包含在混合垃圾回收循环中。默认占用率是65%。这是一个实验性的标志。有关示例,请参阅“ 如何解锁实验性VM标志 ”。此设置取代-XX:G1OldCSetRegionLiveThresholdPercent
设置。此设置在Java HotSpot VM(版本23)中不可用。
-XX:G1HeapWastePercent = 10
设置你愿意浪费的堆的百分比。当可回收百分比小于堆浪费百分比时,Java HotSpot VM不会启动混合垃圾回收循环。默认值是10%。此设置在Java HotSpot VM(版本23)中不可用。
-XX:G1MixedGCCountTarget = 8
在标记周期之后设置混合垃圾收集的目标数量,以收集最多G1MixedGCLIveThresholdPercent
实时数据的旧区域。默认值是8个混合垃圾收集。混合收藏的目标是在这个目标数字之内。此设置在Java HotSpot VM(版本23)中不可用。
-XX:G1OldCSetRegionThresholdPercent = 10
设置混合垃圾回收周期中要收集的旧区域数量的上限。默认值是Java堆的10%。此设置在Java HotSpot VM(版本23)中不可用。
-XX:G1ReservePercent = 10
设置保留内存的百分比以保持空闲状态,以降低发生空间溢出的风险。默认值是10%。当您增加或减少百分比时,请确保将Java堆的总数调整为相同的数量。此设置在Java HotSpot VM(版本23)中不可用。
要更改实验标志的值,您必须先解锁它们。您可以通过-XX:+UnlockExperimentalVMOptions
在任何实验性标志之前在命令行上明确设置。例如:
> java -XX:+ UnlockExperimentalVMOptions -XX:G1NewSizePercent = 10 -XX:G1MaxNewSizePercent = 75 G1test.jar
当您评估和微调G1 GC时,请牢记以下建议:
年轻一代的规模:避免使用-Xmn
选项或任何其他相关的选项(如-XX:NewRatio
。确定年轻一代的规模将超越目标的暂停时间目标。
暂停时间目标:当您评估或调整任何垃圾回收时,始终存在延迟与吞吐量之间的权衡。G1 GC是一个具有统一暂停的增量垃圾收集器,但是在应用程序线程上的开销也更大。G1 GC的吞吐量目标是90%的应用程序时间和10%的垃圾收集时间。当您将其与Java HotSpot VM的吞吐量收集器进行比较时,目标是99%的应用程序时间和1%的垃圾收集时间。因此,当您评估G1 GC的吞吐量时,请放松您的暂停时间目标。设置过于激进的目标意味着您愿意承担垃圾收集开销的增加,这直接影响吞吐量。当您评估G1 GC的等待时间时,您可以设置您所需的(软)实时目标,G1 GC将尝试满足此要求。作为副作用,
驯服混合垃圾收集:调整混合垃圾收集时,请尝试以下选项。有关这些选项的信息,请参阅“ 重要默认值 ”:
-XX:InitiatingHeapOccupancyPercent
为了改变标记阈值。
-XX:G1MixedGCLiveThresholdPercent
以及-XX:G1HeapWastePercent
何时要更改混合垃圾收集的决定。
-XX:G1MixedGCCountTarget
而-XX:G1OldCSetRegionThresholdPercent
当你要调整旧区域的CSet。
当您在日志中看到空间溢出/耗尽的消息时,G1 GC没有足够的内存供生还者或升级对象使用,或者两者兼有。Java堆不能扩展,因为它已经是最大的了。示例消息:
924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space exhausted), 0.1957310 secs]
要么924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space overflow), 0.1957310 secs]
为了缓解这个问题,请尝试以下调整:
增加-XX:G1ReservePercent
选项的值(和相应的总堆)以增加“空间”的保留内存量。
提前开始标记周期,减少-XX:InitiatingHeapOccupancyPercent
。
您也可以增加-XX:ConcGCThreads
选项的值来增加并行标记线程的数量。
有关这些选项的说明,请参阅“ 重要默认值 ”。
对于G1 GC,超过一半区域大小的任何物体都被视为“Humongous物体”。这样一个对象直接分配到老一代到“汉密尔顿地区”。这些Humongous地区是连续的一组地区。StartsHumongous
标志着连续集合的开始,ContinuesHumongous
标志着集合的延续。
在分配任何Humongous区域之前,检查标记阈值,必要时启动并发循环。
在整个垃圾收集周期中,在清理阶段期间,在标记周期结束时,死的Humongous对象被释放。
为了减少复制开销,Humongous物体不包含在任何疏散暂停中。一个完整的垃圾收集周期压缩到位的Humongous物体。
由于每一组独立的开始和连续的黑色区域都只包含一个巨大的对象,所以在对象所跨越的最后一个区域结束之间的空间是未使用的。对于稍大于堆区大小的倍数的对象,此未使用的空间可能会导致堆碎化。
如果你看到由于冗长的分配而启动的背靠背同时循环,并且如果这样的分配将碎片化你的老一代,请增加你的-XX:G1HeapRegionSize
先前的Humongous对象不再是Humongous,并且将遵循正常的分配路径。
G1 GC是一个区域化并行并发增量垃圾收集器,与其他HotSpot GC相比,它提供了更可预测的暂停。增量特性让G1 GC能够处理更大的堆,并且仍然提供合理的最差情况响应时间。G1 GC的自适应特性只需要一个最大的软实时暂停时间目标,以及JVM命令行上Java堆所需的最大和最小大小。