What is a ZGC

The ZGC(Z Garbage Collector) is a low-latency Garbage Collector that was introduced in JDK 11 and has been continuously optimized in subsequent JDK releases.

  1. TB memory is supported
  2. Maximum GC latency is within 10ms (up to 1ms in JDK 16)
  3. Application throughput reduced by up to 15%
  4. Lay the foundation for future GC new features

What follows is a detailed introduction to ZGC and how each of these four features is implemented

Memory layout

Like G1, ZGC uses a region-based heap memory layout, but ZGC’s regions are dynamic: dynamic creation and destruction, dynamic capacity size

There are three regions:

Small Region: the capacity of a Region is fixed at 2MB and stores objects smaller than 256KB

Medium Region: the capacity of medium Region is fixed at 32MB and stores objects larger than 256KB and smaller than 4MB

Large Region: the capacity of a large Region is 2 x N MB and can change dynamically. Each large Region stores only one large object and cannot be redistributed (that is, the object replication described later) because the replication of large objects is expensive

The following figure shows the heap memory layout for ZGC

GC information storage

The traditional way

Part of the data in the heap memory of an object instance is the object header, which consists of Mark Word, pointer to the class and array length. Mark Word records information about objects and locks, and the following image shows its storage structure under a 64-bit JVM.

You can see that GC-related information such as generational age and GC flags is stored in the object header, which is natural in the case of objects being accessed, but objects are often moved in memory for GC reasons, and access failures are possible. We know that objects in memory are accessed through Pointers, so can this GC related information be stored in Pointers? After all, Pointers are much more stable than objects.

Dyeing pointer

A dye pointer is a technique that directly stores a small amount of additional information on a pointer, as shown in the figure below on a 64-bit platform

  • Unused(18 bits) : Indicates an extension point reserved for a future GC feature
  • Finalizable(1 bits) : Flags whether the object will be reclaimed
  • Marked1&Marked0(1 bits each) : Used to mark objects
  • Object Address(42 bits) : 4TB of manageable memory (2 to the 42nd power)

The memory barrier

Memory barriers are a key technique in how dyeing Pointers work. Simply a bit of extra logic when loading a class reference from the heap, doesn’t it have a whiff of AOP?

Object o = obj.fieldA; // Load class references from the heap< memory barrier logic is executed here > Object p = o;// Memory barrier logic is not performed, instead of fetching references from the heap
o.doSomething(); // Memory barrier logic is not performed, instead of fetching references from the heap
Copy the code

The following diagram shows the memory barrier logic, some of which is covered later in this article.

Implementation process

ZGC execution can be divided into four major phases, all of which can be done in parallel

Concurrent tags

Reachability analysis was performed from GC ROOTS traversal object graph

Concurrent preparatory reallocation

Collect statistics of regions that need to be cleared this time and form the regions into Relocation sets.

Concurrent redistribution

This phase copies surviving objects in a Relocation Set to the new Region and maintains a Forward Table for each Region that records the direction from the old object to the new object. Due to the nature of the dye pointer, it is known from the reference alone whether an object is in the Remapped marker. The access is intercepted by the memory barrier, based on the address of the new object in the forwarding table, and the value of the updated reference is corrected to point to the new object. This is the self-healing power of the pointer; only the first access to the old object will be forwarded, that is, only slow once.

After the Region is cleared, it can immediately release the allocation for new objects. There is no need to worry that many Pointers to old objects have not been updated (red arrows in the figure). When the Pointers to old objects access objects, they will be routed to new objects by the forwarding table.

Isn’t it like you visit an old friend (old object), but the old friend has moved (memory copy), but the address of the new home is written on the door (forwarding)?

Concurrent remapping

Remapping is to correct all references to old objects in the heap, but this phase is not urgent due to the self-healing ability, so it is usually performed in conjunction with the Concurrent Mark phase of the next garbage collection cycle, which is to traverse the object graph to save a walk. Once all Pointers have been corrected, the forwarding table that records new and old objects can be released

conclusion

Finally, how are the four official features achieved

TB level of memory: Region partition management and dye pointer addressing

Maximum GC delay time within 10ms: full concurrent processing (only traversal of GC ROOTS will be suspended)

Application throughput is reduced by up to 15% : When the allocation rate of short-lived objects is high, a large number of objects are not being flagged for collection, there is a large amount of floating garbage that affects throughput, and there is less and less space in the heap for transferable objects

Lays the foundation for a future GC feature: coloring unused 18 bits in Pointers

reference

OpenJDK wiki

The Z Garbage Collector Low Latency GC for OpenJDK

The Z Garbage Collector An Introduction

An Introduction to ZGC: A Scalable and Experimental Low-Latency JVM Garbage Collector

In Depth understanding the Java Virtual Machine, third edition