JVM之GC垃圾回收器浅析

JVM之GC垃圾回收器浅析

Wirte by 021. Leave a message if i messed up ! : )

img

对象头

img

GC垃圾回收器的目标

  • 减少GC停顿时间
  • 避免程序崩溃
  • 优化JVM内存空间

GC垃圾回收的主要步骤:

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.

    • 通过并发(并行)标记阶段在老年代寻找存活对象,当Java的堆总内存占用率超过默认的阈值时hotspop虚拟机将触发标记执行阶段
  • Recovering free memory by compacting live objects through parallel copying.

    • 通过并行的 ”复制和压缩存活对象“ 的方式,来恢复和释放可用的内存空间

CMS

  • 基于 标记-清除 算法
  • 适用于老年代
  • 回收过程

    • 初始标记 STW
    • 并发标记
    • 重新标记 STW
    • 并发清除
  • 缺陷

    • 2次STW

    • 内存碎片化

G1 (garbage first 垃圾第一)

Untitled 3

  • 逻辑分代对象

    • eden 新创建的对象(new object)

    • survivor 存活对象

    • old 老年对象

    • humongous 超大对象

官方介绍

  • 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).

特性

  • it collects the regions with the least live data first
    • 优先收集存活对最少的区域
  • 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.

    • G1是区域化和分代的垃圾回收器,堆内存被划分化为大小相等的区域。启动时,虚拟机会设置区域大小。这些区域的大小会根据总堆尺寸被划分为1-32m不同的尺寸。目标是不要超过2048个区域。年轻代,存活代,和老年代,在区域里是逻辑集合,并且并不是连续相邻的.
  • 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.

    • G1 GC 有一个它试图满足的暂停时间的目标,
    • **在年轻代收集期间,G1回收器会调整 年轻代的堆尺寸 来达到 ”暂停时间的预期 目标“. **
    • 在混合混合收集期间,G1回收器会调整 收集过的老年代区域的数量, 基于混合收集器模式预期的目标数量,以及在整个堆每个区域中存活对象的比例,和综合可接受的堆浪费比。

Phases of the Marking Cycle(标记周期的阶段性)

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.

    • 初始化标记阶段(STW): G1 在这个阶段是 从ROOTS开始引用. 这阶段会装载一个普通(STW)的young垃圾回收上。
  • 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.

    • 根区块扫描阶段: G1会扫描 在 (初始标记阶段中 成为old老年代的引用和被老年代引用的对象) 中的survivor存活区块 . 这个阶段是并发运行的应用线程不需要停止,只有当前扫描完成后下一个young垃圾收集才能(STW)开始.
  • 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.

    • 并发标记阶段: G1 在整个堆中寻找可达存活的对象.这个阶段与应用线程并发执行,并且可以被young年轻代垃圾收集器(STW)打断.
  • 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.

    • 重新标记阶段(STW): 这个阶段是为了帮助其完成标记周期的。G1将会清空SATB(Snapshot-At-The-Beginning)的缓冲区,追踪未访问的存活对象,和执行重新引用进程。
  • 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.

    • **清理阶段(STW): 在这最后一步,G1 会执行 计算和清理RSET的STW操作. 在计算期间, G1 会分解出 完整的空闲区块 和 混合垃圾收集的和混合收集器待收集的对象。 清理阶段一定程度上是并发的当 重置和返回空区块到空闲清单 的时候。 **

Garbage Collection Phases(垃圾收集阶段)

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.

  • 下面的两段分别描述了组成 stop-the-world (STW) 的两种回收器, 年轻代回收器与混合回收器,G1 也具备 并发 ,并行 和 联合多相标记周期. G1 使用快照的算法,在标记周期开始之前取得堆中存活对象集合的快照. 快照中的存活对象集合组成了一个集合,并且在开始标记之前这些对象已经被分配好了. G1的标记算法用了前置的写屏障来记录和标记对象来保证对象在物理快照中的一致性。

Young Garbage Collections(年轻代的垃圾收集)

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.

  • G1满足大部分从一个区域添加到年轻代集合区域的内存申请,在年轻代回收期间,G1收集器会同时收集eden区域的垃圾和survivor区域的垃圾从上一个垃圾集中。 eden区和survivor区存活的对象已经被拷贝了,或者已经被撤离出当前区域到了一个的区域集。复制的目标区域是特定的,取决于对象的年龄来决定复制到哪个区块; 一个对象有足够的年龄撤离出eden与survivor到老年区域(这一步是晋升); 另外,如果这个对象撤离到survivor 区 对象的引用会被包含到下一个young 或者 mixed 垃圾集的 cset 中.(CSET标记存活)

Mixed Garbage Collections (混合垃圾收集)

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.

  • 在成功完成并发标记周期的基础上,G1 从 执行年轻代垃圾收集切换到执行混合垃圾收集。在混合的垃圾收集模式中,G1选择性的添加一些老年代区块到已经被收集了的young和survivor的区块中. 一个标志数字控多少准确个老年代会被添加到已经被清空的新区块中;在G1 收集了足够多的old区块(在多个混合的垃圾集合中),G1 会切换执行young代的垃圾收集直到下一个标记周期完成.
  • 核心算法实现

    • Rset (Remember Set) 引用记忆集

      • 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.

      • G1垃圾回收器使用独立的记忆集来追踪区域里的引用,独立的RSET允许并行,并且 每个区域的RSET是独立的,因为只有当前区域的RSET为了扫描引用才必须进入当前区域,从而避免全堆扫描。垃圾回收器利用后置写屏障来标记记录堆更改和RSET的更新.

    • Cset(Collection Set)存活收集集

      • 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.
      • 垃圾收集器为了减少堆内存碎片,将一组或多组区域的存活对象并行复制到不同的新区域来实现内存整理压缩.

Important Defaults (官方文档)

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

    1
    2
    3
    4
    5

    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

    1
    2
    3
    4
    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](https://www.oracle.com/technical-resources/articles/java/g1gc.html#Unlock)" 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

    1
    2
    3
    4
    5
    6
    7

    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

    1
    2
    3
    4
    5

    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

    1
    2
    3
    4
    5

    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

    1
    2
    3
    4
    5

    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.

How to Unlock Experimental VM Flags

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:

1
> java -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=10 -XX:G1MaxNewSizePercent=75 G1test.jar

Recommendations

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.

Overflow and Exhausted Log Messages

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:

1
924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space exhausted), 0.1957310 secs]

OR

1
924.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.

Humongous Objects and Humongous Allocations

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.

Conclusion

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.

See Also

About the Author

Monica Beckwith, Principal Member of Technical Staff at Oracle, is the performance lead for the Java HotSpot VM’s Garbage First Garbage Collector. She has worked in the performance and architecture industry for over 10 years. Prior to Oracle and Sun Microsystems, Monica lead the performance effort at Spansion Inc. Monica has worked with many industry standard Java based benchmarks with a constant goal of finding opportunities for improvement in the Java HotSpot VM.

王者ZGC

  • 回收过程

    • 初始标记 STW

    • 并发标记

    • 并发转移STW

  • 核心算法

    • 标记对象指针

      • 暂时可以理解为在64位内存地址中取三个标志位映射对象的同一块物理内存地址,标记对象的标记过程,重新定位过程,等GC回收标志
    • 合理利用64位处理器架构 ,Numa架构

      • 现在多CPU插槽的服务器都是Numa架构,比如两颗CPU插槽(24核),64G内存的服务器,那其中一颗CPU上的12个核,访问从属于它的32G本地内存,要比访问另外32G远端内存要快得多。
    • 读屏障

      • 因为在标记和移动过程中,GC线程和应用线程是并发执行的,所以存在这种情况:对象A内部的引用所指的对象B在标记或者移动状态,为了保证应用线程拿到的B对象是对的,那么在读取B的指针时会经过一个 “load barriers” 读屏障,这个屏障可以保证在执行GC时,数据读取的正确性。
    • Compacting 内存页压缩