Garbage Collector II of JVM Garbage Collection Series

essay

In the past two weeks, due to the busy company's project launch, the published articles will appear to be mediocre, so I apologize
insert image description here

introduction

This article will introduce G1GC in HotSpot

Reference book: "In-depth understanding of Java Virtual Machine"

Personal java knowledge sharing project - gitee address

Personal java knowledge sharing project - github address

G1GC

introduce

G1 (Garbage First) is a garbage collector for server applications. It is mainly aimed at machines equipped with multi-core CPUs and large-capacity memory. It meets the GC pause time with a high probability and also has high-throughput performance characteristics. It was officially launched in JDK1.7 version, and the Experimental logo was removed. It is the default garbage collector after JDK 9, replacing the CMS collector and the combination of Parallel+ParallelOld. It is officially called a "full-featured garbage collector" by Oracle. At the same time, CMS has been marked as deprecated in JDK 9. It is not the default garbage collector in JDK8, you need to use -XX:UseG1GC to enable it. In the HotSpot garbage collector, except G1, other garbage collectors use the built-in JVM thread to perform GC multi-threaded operations, while G1 GC can use the application thread to undertake the GC work running in the background, that is, when the JVM GC thread processing speed is slow , the system invokes application threads to help speed up the garbage collection process.

doubt:

1. Since we already have the previous powerful GCs, why release Garbage First (G1) GC?

Answer: The reason is that the business of the application program is becoming larger and more complex, and there are more and more users. Without GC, the normal operation of the application program cannot be guaranteed, and the GC of STW often cannot keep up with the actual demand. Will continue to try to optimize the GC. The G1 (Garbage First) garbage collector is a new garbage collector introduced after Java 7 update 4, and is one of the most cutting-edge achievements in the development of today's collector technology. At the same time, in order to adapt to the ever-expanding memory and increasing number of processors, the temporary time (Pause Time) is further reduced, while taking into account good throughput. The official goal set for G1 is to obtain the highest possible throughput while the delay is controllable, so it is the responsibility and expectation of a "full-featured collector".

2. Why is it called Garbage First (G1)?

Answer: Because G1 is a parallel collector, it divides the heap memory into many irrelevant regions (Regions) (physically discontinuous). Use different Regions to represent Eden, Survivor 0, Survivor 1, Old Generation, etc. The G1 GC programmatically avoids region-wide garbage collection on the entire Java heap. G1 tracks the value of garbage accumulation in each Region (the size of the space obtained by recycling and the experience value of the time required for recycling), and maintains a priority list in the background. Each time, according to the allowed collection time, the Region with the longest value is preferentially recycled. Since the focus of this method is to recycle the area with the largest amount of garbage (Region), we give G1 a name: Garbage First (GarbageFirst)

features

G1 is a garbage collector for server-side applications. The mission entrusted by the HotSpot development team is to replace the CMS collector released in JDK 1.5 (in the relatively long term) in the future. Compared with other GC collectors, G1 has the following characteristics:

  • Parallel and concurrent
    • Parallelism: During G1 recycling, multiple GC threads can work simultaneously to effectively utilize multi-core computing power. At this point the user thread STW
    • Concurrency: G1 has the ability to execute alternately with the application, and part of the work can be executed at the same time as the application. Therefore, generally speaking, the application will not be completely blocked during the entire recycling phase.
  • Generational collection
    • From the perspective of generation, G1 is still a generational garbage collector, which distinguishes the young generation from the old generation. The young generation still has Eden and Survivor areas. But from the perspective of the heap structure, it does not require the entire Eden area, the young generation or the old generation to be continuous, and it no longer insists on a fixed size and a fixed number.
    • Divide the heap space into several regions (Regions), which contain the logical young generation and old generation.
    • Unlike previous types of collectors, it takes care of both the young generation and the old generation at the same time. Compared with other collectors, either work in the young generation or work in the old generation;
  • spatial integration
    • CMS: "mark-clear" algorithm, memory fragmentation, defragmentation after several times
    • G1 divides memory into regions. The recovery of memory is based on the region as the basic unit. There is a copy algorithm between Regions, but it can actually be regarded as a mark-compression (Mark-Compact) algorithm as a whole. Both algorithms can avoid memory fragmentation. This feature is conducive to the long-running of the program. When allocating large objects, the next GC will not be triggered in advance because no continuous memory space can be found. Especially when the Java heap is very large, the advantages of G1 are more obvious.
  • Predictable pause time model (ie: soft real-time)
    • This is another major advantage of G1 over CMS. In addition to pursuing pauses, G1 can also establish a predictable pause time model, allowing users to clearly specify a time segment of M milliseconds to spend on garbage collection The time must not exceed N milliseconds. Due to partitioning, G1 can only select some areas for memory recycling, which narrows the scope of recycling, so the occurrence of global pauses can also be better controlled. G1 tracks the value of garbage accumulation in each Region (recycling The size of the acquired space and the experience value of the time required for recycling), maintain a priority list in the background, and give priority to recycling the Region with the highest value according to the allowed collection time each time. It ensures that the G1 collector can obtain the highest possible collection efficiency within a limited time. Compared with CMS GC, G1 may not be able to achieve the delay pause of CMS in the best case, but the worst case is much better.

The collection range of other collectors before G1 is the entire new generation or the old generation, but this is no longer the case with G1. When using the G1 collector, the memory layout of the Java heap is very different from other collectors. It divides the entire Java heap into multiple independent regions (Regions) of equal size, although the concepts of the new generation and the old generation are still retained. , but the new generation and the old generation are no longer physically isolated, they are all part of the Region (does not need to be continuous) collection.

The reason the G1 collector can model predictable pause times is because it can programmatically avoid full-area garbage collections on the entire Java heap. G1 tracks the value of garbage accumulation in each Region (the size of the space obtained by recycling and the experience value of the time required for recycling), maintains a priority list in the background, and gives priority to recycling the Region with the largest value ( This is where the name Garbage-First comes from). This method of using Region to divide memory space and prioritized region recovery ensures that the G1 collector can obtain the highest possible collection efficiency within a limited time.

Partition Region: Divide into zero

When using the G1 collector, it divides the entire Java heap into about 2048 independent Region blocks of the same size. The size of each Region block depends on the actual size of the heap space, and the overall control is between 1MB and 32MB, and is 2 The Nth power, namely 1MB, 2MB, 4MB, 8MB. It can be set by -XX:G1HeapRegionSize. All Regions are the same size and will not change during the JVM lifetime.

Although the concepts of the new generation and the old generation are still retained, the new generation and the old generation are no longer physically isolated. They are all a collection of a part of Regions (does not need to be continuous). Logical continuity is achieved through the dynamic allocation of Regions. A region may belong to Eden, Survivor or Old/Tenured memory area. But a region can only belong to one role. E indicates that the region belongs to the Eden memory area, s indicates that it belongs to the Survivor memory area, and o indicates the Old memory area. A region may belong to Eden, Survivor or Old/Tenured memory area. But a region can only belong to one role. E indicates that the region belongs to the Eden memory area, s indicates that it belongs to the Survivor memory area, and o indicates the Old memory area. The G1 garbage collector also adds a new memory area called the Humongous memory area. It is mainly used to store large objects. If there are more than 1.5 regions, it will be placed in H.

Reasons for setting H:

For large objects in the heap, they will be directly allocated to the old generation by default, but if it is a short-lived large object, it will have a negative impact on the garbage collector. To solve this problem, G1 divides a Humongous area, which is used to store large objects. If an H area cannot hold a large object, then G1 will look for continuous H areas as part of the old generation. In order to find continuous H areas, sometimes Full GC has to be started. Most of the behavior of G1 treats the H area as part of the old generation.

G1's idea of ​​"dividing memory into parts" seems easy to understand, but the implementation details are far from as simple as imagined, otherwise it would not start from the first G1 paper published by Sun Lab in 2004 A commercial version of the G1 has not been developed until today (nearly 10 years). The author takes a detail as an example: After the Java heap is divided into multiple Regions, can garbage collection really be carried out in units of Regions? It sounds logical, and if you think about it carefully, it is easy to find the problem: Regions cannot be isolated. An object is allocated in a certain Region, it can be referenced by other objects in this Region, but can have a reference relationship with any object in the entire Java heap. Then when making reachability judgments to determine whether the object is alive, wouldn’t it be necessary to scan the entire Java heap to ensure accuracy? This problem is not unique to G1, but it is more prominent in G1. In previous generational collections, the size of the new generation is generally much smaller than that of the old generation, and the collection of the new generation is much more frequent than that of the old generation. The same problem is faced when recycling objects in the new generation. If the old generation has to be scanned at the same time, the efficiency of Minor GC may drop a lot.

In the G1 collector, the virtual machine uses Remembered Set to avoid full heap scans for object references between Regions and object references between the new generation and the old generation in other collectors. Each Region in G1 has a corresponding Remembered Set. When the virtual machine discovers that the program is writing the data of the Reference type, it will generate a Write Barrier to temporarily interrupt the writing operation, and check whether the object referenced by the Reference is in a different Region. Among them (in the example of generation, it is to check whether the object in the old generation refers to the object in the new generation), if so, record the relevant reference information into the Remembered Set of the Region to which the referenced object belongs through CardTable. When performing memory recovery, adding Remembered Set to the enumeration range of the GC root node can ensure that the whole heap will not be scanned and there will be no omissions.

garbage collection process

The garbage collection process of G1 GC mainly includes the following three links (ignoring the Remembered Set process):

  1. Young GC (Young GC)
  2. Old Age Concurrent Marking Process (Cocurrent Marking)
  3. Mixed GC (Mixed GC) (If necessary, the single-threaded, exclusive, high-intensity Full GC still exists. It provides a failure protection mechanism for GC evaluation failures, namely strong recycling.)

The application allocates memory, and starts the young generation collection process when the Eden area of ​​the young generation is exhausted: the young generation collection phase of G1 is a parallel exclusive collector. In the young generation collector, G1 GC suspends all application threads and starts multiple threads to perform young generation collection. Then move the surviving objects from the young generation interval to the Survivor interval or the old interval, or both intervals may be involved. When the heap memory usage reaches a certain value (45% by default), the concurrent marking process of the old generation starts. Once the marking is complete, the mixed recovery process begins immediately. For a hybrid collector, the G1 GC moves from the old generation to live objects to free regions, which become part of the old generation. Unlike the young generation, the old generation G1 collector is different from other GCs. The G1 old generation collector does not need to recycle the entire old generation. It only needs to scan/recycle a small part of the old generation Region at a time. At the same time, the old generation Region is recycled together with the young generation. For example: a web server, the Java process has a maximum heap memory of 4G, responds to 1500 requests per minute, and allocates about 2G of memory every 45 seconds. G1 will recycle the young generation every 45 seconds, and the usage rate of the entire heap will reach 45% every 32 hours. It will start the concurrent marking process of the old generation, and start four to five mixed collections after the marking is completed.

G1 recycling process 1: young generation GC
  • The first stage, scanning the root
    • The root refers to the object pointed to by the static variable, the local variable on the method call chain being executed, and so on. The root reference, together with the external references recorded by the RSet, are used as the entry point for scanning surviving objects.
  • The second stage, update RSet
    • Process the cards in the dirty card queue (see remarks) and update the RSet. After the second stage is completed, RSet can accurately reflect the references of the old generation to the objects in the memory segment where it is located
    • For the application's reference assignment statement Object.field = object, the JVM will perform special operations before and after to enqueue a card that holds the object reference information in the dirty card queue. When the young generation recycles, G1 will process all the cards in the Dirty Card Queue to update the RSet to ensure that the RSet can accurately reflect the reference relationship in real time
    • Then why not directly follow the new RSet at the reference assignment statement? This is for performance needs. The processing of RSet requires thread synchronization, which will cause a lot of overhead, and the performance of using queues will be much better.
  • The third stage, processing RSet
    • Identify the objects in Eden that are pointed to by the old generation objects. These objects in Eden that are pointed to are considered to be surviving objects
  • The fourth stage, the replication stage
    • At this stage, the object tree is traversed, and the surviving objects in the memory segment of the Eden area will be copied to the empty memory segment in the Surviror area. Copy to an empty memory segment in the Old area. If the Survivor space is not enough, part of the data in the Eden space will be directly promoted to the old generation space.
  • The fifth stage, processing references
    • Handle references to Soft, Weak, Phantom, Final, JNI Weak, etc. In the end, the data in the Eden space is empty, the GC stops working, and the objects in the target memory are stored continuously without fragmentation, so the copy process can achieve the effect of memory organization and reduce fragmentation.
G1 recycling process 2: concurrent marking process
  • Initial marking phase: mark objects that are directly reachable from the root node. This phase is STW and triggers a young generation GC.
  • Root Region Scanning (Root Region Scanning): G1 GC scans the objects in the old age region that are directly reachable in the Survivor region, and marks the referenced objects. This process must be completed before Young GC.
  • Concurrent Marking: Concurrent marking is performed on the entire heap (concurrent execution with the application), this process may be interrupted by Young GC. During the concurrent marking phase, if all objects in the area object are found to be garbage, the area will be recycled immediately. At the same time, during the concurrent marking process, the object liveness (proportion of surviving objects in the region) is calculated for each region.
  • Remarking (Remarking): As the application continues, the last marking result needs to be corrected. It's from STW. G1 uses an initial snapshot algorithm faster than CMS: snapshot-at-the-beginning (SATB).
  • Exclusive cleanup (cleanup, STW): Calculate the proportion of surviving objects and GC recovery in each area, and sort them to identify areas that can be mixed and recovered. Pave the way for the next stage. It's from STW.
    • This phase does not actually do garbage collection.
  • Concurrent cleanup phase: completely free regions are identified and cleaned up.
G1 recycling process three: mixed recycling

After the concurrent marking ends, the memory segments that are 100% garbage in the old generation are reclaimed, and the memory segments that are partially garbage are calculated. By default, these memory segments in the old generation will be divided into 8 times (you can set by -XX:G1MixedGCCountTarget) is recycled. The collection set of mixed recovery includes one-eighth of the memory segments of the old age, the memory segments of the Eden area, and the memory segments of the Survivor area. The mixed recycling algorithm is exactly the same as the young generation recycling algorithm, except that the old generation memory segments are added to the recycling collection. For details, please refer to the Young Generation Recycling Process above. Since the memory segments in the old generation are recycled 8 times by default, G1 will give priority to recycling the memory segments with more garbage. The higher the ratio of garbage to the memory segment, the more it will be recycled first. And there is a threshold that will determine whether the memory segment is reclaimed, -XX: G1MixedGCLiveThresholdPercent defaults to 65%, which means that the garbage memory segment ratio will reach 65% before it will be reclaimed. If the proportion of garbage is too low, it means that the proportion of surviving objects is high, and it will take more time to assign values. Mixed recovery does not have to be performed 8 times. There is a threshold -XX:G1HeapWastePercent, the default value is 10%, which means that 10% of the entire heap memory is allowed, and no mixed recycling will be performed. Because GC takes a lot of time but reclaims very little memory.

G1 recycling process four: Full GC (optional process)

The original intention of G1 is to avoid the occurrence of Full GC. However, if the above method does not work properly, G1 will stop the execution of the application (Stop-The-World), and use a single-threaded memory recovery algorithm for garbage collection. The performance will be very poor, and the application pause time will be very long. To avoid the occurrence of Full GC, adjustments need to be made once it occurs. When will Full GC happen? For example, if the heap memory is too small, when G1 has no empty memory segments available when copying surviving objects, it will fall back to Full GC. This situation can be solved by increasing the memory.

There may be two reasons for G1Full GC:

  • During Evacuation, there is not enough to-space to store promoted objects;
  • Space was exhausted before concurrent processing was complete.

Then paste the operation diagram of the G1 collector in "In-depth understanding of the java virtual machine":
insert image description here

Judging from the above introduction to G1, G1 is undoubtedly very powerful, but it is not a universal garbage collector. Compared with CMS, G1 does not have all-round and overwhelming advantages. For example, during the running of the user program, G1 is higher than CMS in terms of the memory usage (Footprint) generated by garbage collection and the additional load (Overload) when the program is running. From experience, the performance of CMS in small-memory applications is likely to be better than G1, and G1 will play its advantages in large-memory applications. The balance point is between 6-8GB.

Parameter settings of the G1 recycler:

  • -XX:+UseG1GC Manually specify to use the G1 collector to perform memory recovery tasks.
  • -XX:G1HeapRegionSize sets the size of each Region. The value is a power of 2, the range is between 1MB and 32MB, and the goal is to divide about 2048 regions according to the minimum Java heap size. The default is 1/2000 of the heap memory.
  • -XX: MaxGCPauseMillis Set the expected maximum GC pause time indicator (JVM will try its best to achieve it, but it is not guaranteed). The default value is 200ms
  • -XX: ParallelGCThread sets the number of STW worker threads. Set n to about 1/4 of the number of parallel garbage collection threads (ParralelGCThread).
  • -XX:InitiationHeapOccupancyPercent sets the Java heap occupancy threshold that triggers concurrent GC cycles. If this value is exceeded, GC is triggered. The default value is 45

Applicable scenarios for the G1 collector:

  • For server-side applications, for machines with large memory and multiple processors. (not surprising performance on normal sized heaps)
  • The main applications are applications that require low GC latency and have a large heap to provide a solution. For example: when the heap size is about 6GB or larger, the predictable pause time can be less than 0.5 seconds; (G1 only cleans up a part of the region instead of all the incremental cleanup each time to ensure that each GC pause time will not too long).
  • It is used to replace the CMS collector in JDK1.5. In the following cases, using G1 may be better than CMS:
    • More than 50% of the Java heap is occupied by active data;
    • Object allocation frequency or age promotion frequency varies greatly;
    • GC pauses are too long (longer than 0.5 to 1 second)

Guess you like

Origin blog.csdn.net/a_ittle_pan/article/details/127720746