Garbage collectors are not specified much in the JVM specification, so there are different implementations from different vendors.
In the rapid iteration of the JDK, numerous garbage collectors were developed, which could be divided into serial and parallel garbage collectors by number of threads.
Serial collection means that only one CPU is allowed to perform garbage collection at a time, and the worker thread is suspended until the garbage collection is complete.
Serial collection may appear to be inefficient in a single thread, but in scenarios where hardware platforms such as embedded (with a small number of cores) are not particularly superior, serial collection can outperform the parallel collector. Therefore, serial collection is applied by default to the JVM in Client mode on the Client side
In contrast to serial collection, parallel collection can use multiple CPU cores to perform garbage collection, thus improving application throughput.
According to the working mode, can be divided into parallel and exclusive garbage collector
And the heuristic collector works alternately with application threads to minimize application pause time.
Once run, the exclusive collector stops all user threads in the application to improve GC efficiency and increase throughput.
Garbage collectors can be classified into compressed and non-compressed garbage collectors according to their fragmentation handling methods
After the collection is complete, the surviving objects are compressed to eliminate memory fragmentation.
The uncompressed garbage collector does not operate.
According to the working memory area, can be divided into young generation and old generation garbage collector
The Cenozoic GC is serialized, ParNew, Parallel Exploiture, and G1.
There are Serial Old GC, Parallel Old GC, CMS GC, G1 GC
Because of the frequent garbage collection in the new generation, it is more efficient to use the parallel way, while in the old age, there are few garbage collection and many surviving objects, and the serial collection can save resources (even a single core can do it).
Serial
Serial is the most basic and oldest single-threaded (Serial) garbage collector, the only choice for generations prior to JDK1.3;
In the hardware market of the 1990s, where most cpus were single-core, the single-threaded garbage collector was the best choice to avoid performance degradation caused by concurrent contention. To date, this collector is still the default version of the new generation JDK in Client mode.
Serial uses a copy algorithm for garbage collection, STW at run time. In addition to the new generation, the collector also works on the Old version of Serial, which uses a tag compression algorithm.
Serial Old is primarily used in conjunction with the Parallel Insane and as a backup garbage collector for CMS.
Advantages:
Simple and efficient, Serial is not as efficient and efficient as other thread interactions for a single CPU environment
In the Java application on the client side, the hardware level of the computer is not high, the memory is not large (tens of megabytes to one or two hundred megabytes), even the single thread garbage collection also has a very low delay.
Pass -xx :UseSerialGC to specify that both young and old generations are using Serial collector. You can run -xx :+PrintCommandLineFlags to check the parameters related to the command line (including the garbage collector) or run jinfo-flag UseSerialGC pid to check whether the parameters are used. Pid indicates the ID of the Java process.
ParNew
ParNew is the multithreaded version of Serial. ParNew is a parallel collector, Par is parallel, New is the New generation, obviously, this collector can only be used in the New generation.
Compared with Serial, ParNew has no difference except that it adopts parallel recycling, and also adopts the replication algorithm, which will also cause STW. ParNew is not necessarily more efficient than Serial, as single-core machines are not.
ParNew and the Parallel Insane are both Parallel garbage collectors, but the underlying implementation is different; only ParNew can be used with the CMS.
You can use -xx :+UseParNewGC to manually specify ParNewGC for garbage collection, but only for the new generation. Since the collection is parallel, you can use -xx: ParallelGCThreads to set the number of threads that perform the collection. If you do not set this value, it defaults to the same number of CPU threads.
Parallel
The Parallel Avenge avenge is a collector that uses a replication algorithm to run the STW insane, the new generation the Parallel Avenge, and the older generation the Parallel Avenge.
Parallel Old is introduced in JDK1.6, which uses tag compression algorithm to replace Serial Old. The two Parallel models are the default combination of JDK1.8 and have excellent performance in Server mode
Parallel and ParNew are both Parallel collectors, so is Parallel redundant when ParNew already exists? Not really, their underlying implementation code is quite different, and Parallel is more focused on improving application throughput and setting adaptive policies.
High-throughput GC is suitable for tasks that do not require much interaction, such as batch processing, order processing, payroll, scientific computing, and so on.
Related parameters:
-XX:+UseParallelGC
Manually specify the younger generation to use the Parallel Explogc and the older generation-XX:+ParallelOldGC
When one of the two parameters is turned on, the other is also activated (mutually activated).-XX:ParallelGCThreads
By default, the CPU core is less than 8, the same as the number of cores. When greater than 8, ParallelGCThreads = 3+(5 * CPU_threads /8).-XX:MaxGCPauseMillis
, sets the maximum pause time for the garbage collector in milliseconds,Use this parameter with caution.-XX:GCTimeRatio
The value is (0,100). The default value is 99, which means that the garbage collection time is less than 1%. There is a certain contradiction with -xx :MaxGCPauseMillis. The longer the tentative time, the ratio will easily exceed the specified ratio.-XX:+UseAdaptiveSizePolicy
To set the adaptive adjustment policy. In this mode, the ratio of Eden to Survivor, and the advancing age of older objects are automatically adjusted to reach a balance between heap size, throughput, and pause time. In cases where manual tuning is difficult, you can use this parameter by specifying it-Xmx
,GCTimeRatio
andMaxGCPauseMillis
, and let the virtual machine do the tuning itself.
CMS
CMS is a Concurrent Mark Sweep designed to Sweep garbage and user threads simultaneously. CMS is a Concurrent Mark Sweep designed to Sweep garbage and user threads simultaneously. CMS is a Concurrent Mark Sweep designed to Sweep garbage and user threads simultaneously
At the beginning of CMS design, the focus was to minimize the pause time of user threads during garbage collection. It can be used for applications that attach importance to service response speed and want the shortest system pause time.
- Initial Mark
At this stage, all user threads in the program will be suspended, and then the objects that GC Roots can be directly associated with at the GC thread mark will be resumed once the mark is completed. As there are fewer objects directly associated with the program, the speed is very fast.
- Concurrent Mark
Starting with the directly associated objects of GC Roots, the entire object tree is traversed, a time-consuming process that does not require the user thread to be paused.
- Re-mark (Remark)
During the concurrent marking phase, the user thread is still running, and you need to fix the part of the object record where the tag changes because the user thread is running during the concurrent marking phase. This process takes longer than the initial tag, but less time than the concurrent tag.
- Concurrent Sweep
Clearing dead objects judged by the marking phase frees up memory, and since there is no need to move live objects, this phase also runs concurrently with the user thread.
- Reset the thread
Resets the state of the GC thread
Although CMS adopts concurrent collection, it still causes STW in the initial marking and re-marking phases, so it just minimizes pause time as much as possible. The most time-consuming concurrent tagging and concurrent cleanup phases do not require suspending the user thread, so the overall recycle pause time is relatively short.
However, the CMS needs to ensure that the user thread has enough memory during the collection process, so the CMS cannot wait until the memory is full before garbage collection. Instead, the CMS collects garbage when the memory usage reaches a certain threshold to ensure that the user thread still has enough memory space to run when the CMS is working. A Concurrent Mode Failue occurs if the memory set aside during a CMS run cannot meet the needs of the user’s threads. This is when the JVM starts a fallback and starts the Serial Old collector to redo the Old garbage collection, resulting in a longer pause.
The CMS garbage collector uses a marker clearing algorithm. After each GC, the cleared object space is discontinuous, resulting in some memory fragmentation. Therefore, CMS will not be able to use The Bump The Pointer technique when allocating memory for new objects. Instead, it will have to choose The Free List to allocate memory. So why don’t CMS use a tag compression algorithm? In the compression phase, the living objects need to be moved, which will cause STW. In the old era, there are many living objects, and this process will be very time-consuming.
Note that A CMS cannot work with the Parallel Insane, only use Serial or ParNew.
CMS benefits are obvious, concurrent collection, can run with user threads; Have short pause times. The disadvantage is that the use of token clearing algorithm is prone to memory fragmentation and can cause Full GC when large objects cannot be allocated. In the concurrent phase, CPU resources are competing with user threads, resulting in slower applications and reduced GC throughput. It is also unable to handle floating garbage and may result in a Concurrent Mode Failure, where new garbage objects are generated by user threads in the Concurrent cleanup phase and can only be collected by CMS until the next garbage collection.
Related parameters:
-
-xx :+UseConcMarkSweepGC: manually specifies the CMS to perform garbage collection tasks. After this parameter is enabled, the CMS is automatically enabled. -xx :UseParNewGC indicates that the new generation uses ParNew and the old generation uses CMS. When this parameter is used in JDK9, you get a warning that the CMS will be deprecated in the future. When used in JDK14, the JVM is started in the default GC mode.
-
– XX: CMSInitiatingOccupanyFraction, set the heap memory usage threshold, after reaching the threshold for garbage collection.
The default is 68(68%) for versions prior to JDK5 and 92 for versions after JDK6
If memory growth is slow, a slightly larger value can be set to reduce the frequency of CMS GC. If memory is growing rapidly, you should lower this threshold, or you may cause Full GC.
-
– XX: + UseCMSCompactAtFullCollection, specify the execution of the Full after GC to compress the memory space, avoid memory fragments produced at a time, but due to the memory compression cannot execute concurrently, after Full GC will cause a pause time.
-
How many times – XX: CMSFullGCsBeforeCompaction, set to perform Full GC to compress the memory space after finishing.
-
-xx :ParallelCmsThreads sets the number of threads in the CMS. The default is (ParallelGCThreads + 3)/4. ParallelGCThreads is the number of threads for the younger generation of parallel collectors. When CPU resources are tight, application performance is affected by the CMS collection threads during the garbage collection phase.
Common combinatorial relationships between GC’s
Serial: Serial, Serial Old
Avenge: ParNew, Parallel Avenge, Parallel Old
Concurrency: CMS, G1(both parallel)
The G1 garbage collector works on the entire heap.
The Serial GC and CMS GC, ParNew GC and Serial Old GC in the yellow dotted line are deprecated in Java8 and removed in Java9. Parallel GC and Serial Old GC are deprecated in Java14 and are expected to be removed in the near future.
The solid black lines in the figure associate the CMS GC with the Serial Old GC, indicating that the Serial Old GC is an alternative to the CMS GC
GC performance Index
- throughput
The ratio of time spent running user code to total elapsed time (user elapsed time + memory reclaim time)
For example, if the virtual machine ran for 10 minutes and garbage collection took 10 seconds, the throughput would be 99.98%.
- The pause time
The time at which the user thread is suspended while garbage collection is being performed
From the user’s point of view, the pause time of GC is particularly important, even a 0.2s GC can affect the interactive experience. For some top services, the response time is even limited to 20ms at a time, and GC pause times can become a serious bottleneck.
Throughput vs. pause time:
It can be concluded from the figure that if throughput is the priority, the execution frequency of memory reclamation must be reduced. By taking pause time first, garbage collection can only be done frequently, resulting in reduced throughput.
A common criterion is to minimize pause times while maximizing throughput.
- Memory footprint
The size of memory occupied by the JVM heap area
- Garbage collection overhead
The complement of throughput, the ratio of garbage collection time to total elapsed time
- Collect frequency
How often garbage collection occurs over a period of time
- speed
The time an object takes from birth until it is reclaimed
Of these metrics, pause times, throughput, and memory footprint form an “impossible triangle,” meaning that a good garbage collector is best at satisfying both of them. As hardware technology has evolved, server memory has increased and tolerance of memory usage has increased, so in practice throughput and pause times are the most important concerns
A brief history of garbage collector development
In 1999, the first Serial GC came out in JDK1.3.1. ParNew GC is a multithreaded version of Serial GC
In 2002, JDK1.4.2, Parallel GC and Concurrent Mark Sweep GC were released. Parallel GC became the default GC for HotSpot after JDK6
In 2012, JDK 1.7 introduced the G1 GC
In 2017, JDK8, G1 GC replaced CMS as the default GC
In 2018, JDK11 introduced the Epsilon GC, which is also known as the no-OP operation-free collector, and also released the ZGC
In 2019, JDK12, improved G1 collector, released Shenandoah GC
In 2019, JDK13, improved ZGC
In 2020, JDK14 will remove CMS GC and expand ZGC application on Mac and Win