CMS is an old-time garbage collector that can operate concurrently with user threads during collection. It can be used in conjunction with the Serial collector and Parallel New collector. CMS sacrifices system throughput in pursuit of collection speed and is suitable for servers that pursue garbage collection speed. CMS can be started with the JVM startup parameter: -xx :+UseConcMarkSweepGC.

CMS Collection Process

The CMS process has seven steps:

  1. Initial mark (CMS-initial-mark), which results in STW;
  2. Concurrent mark (cmS-concurrent-mark), which runs concurrently with the user thread;
  3. Preclean (cmS-concurrent-preclean), running at the same time as the user thread;
  4. Abortable preclean (cmS-concurrent-abortable-preclean) runs at the same time as the user thread;
  5. Re-marking (CMS-remark) will result in SWT;
  6. Concurrent sweep (cmS-concurrent-sweep), which runs concurrently with the user thread;
  7. Concurrent state reset waits for the next CMS trigger (cms-concurrent-reset), running concurrently with the user thread; Its operation flow chart is as follows:

Initial tag

This is one of two stop-the-world events in CMS. This step marks alive objects and has two parts:

  1. Mark all GC Roots objects in the old age, node 1 in the figure below;
  2. Nodes 2 and 3 in the figure below mark objects of the old age referenced by living objects in the young generation (referring to objects of the reference type that are alive in the young band and refer to objects in the old age).

Concurrent tags

Find all surviving objects starting with those marked in the “initial mark” phase; Because it is run concurrently, during operation, objects of the new generation will be promoted to the old age, or directly assigned to the old age, or update the reference relationship of the old age object, etc. For these objects, they need to be re-marked, otherwise some objects will be omitted and the mark will be missed. In order to improve the efficiency of re-marking, the Card where the above objects reside is identified as Dirty. In the future, only the objects of these Dirty cards are scanned, avoiding scanning the whole old age. The concurrent marking stage is only responsible for marking the Card whose reference has been changed as Dirty, and is not responsible for processing; Nodes 1, 2, and 3, as shown below, eventually find nodes 4 and 5. The characteristic of the concurrent tag is to run concurrently with the application thread. Not all living objects from older generations will be marked, as the application will change some object references and so on. Because this phase is concurrent with the user thread, a concurrent mode failure can occur.

Pre-cleaning stage

Previous stage has shown, it is not marked the old s all live objects, because of the tag application will change some object reference at the same time, the stage is used to deal with the previous stage the no tag because the reference relationship changed to the survival of the object, it will scan all Card marked as Dirty as shown in the figure below, in concurrent clean up the stage, The reference to node 3 points to 6; The card on node 3 is marked as Dirty.

Terminable preprocessing

This stage tries to undertake enough work for the next stage Final Remark stage. The duration of this phase depends on a number of factors, since this phase is repeated until one of the abort conditions (e.g., number of repetitions, amount of work, duration, etc.). Ps: The maximum duration of this stage is 5 seconds. Another reason why this stage can last for 5 seconds is to expect a YGC to occur within 5 seconds to clear references of the young band. In the next stage of re-marking, the time of scanning references of the young band pointing to the old era is reduced.

To mark

This phase results in a second Stop the Word phase, where the task is to finish marking all living objects for the entire ten-year-old generation. At this stage, the memory scope for re-marking is the entire heap, including _young_gen and _old_gen. If objects in the old generation are referenced by objects in the new generation, they will be regarded as living objects. Even if objects in the new generation are unreachable, unreachable objects will be used as the “GC root” of CMS to scan the old generation. Therefore, for the old age, objects of the new generation that reference objects of the old age will also be regarded by the old age as “GC ROOTS” : when this stage takes a long time, you can add the parameter -xx :+CMSScavengeBeforeRemark, and perform yGC before re-marking. Recycle the useless objects of the young band, and put the objects into the survival band or promote to the old age, so that the scan of the young band, only need to scan the objects of the survival zone, generally very small, which greatly reduces the scanning time. Since the previous pre-processing stage is executed concurrently with the user thread, many changes may have taken place in the reference of the young object to the old age. At this time, it will take a lot of time to process these changes in the remark stage, which will lead to a long stop of the word. So CMS usually tries to run Final Remark when the young generation is clean enough. The parallel collection can also be enabled: -xx :+ CMSPARallelEnabled.

Concurrent cleaning

With the above five phases of tagging, all surviving objects from the old age have been tagged and the unusable objects are now scavenged through a Garbage Collector. This phase is mainly about clearing unmarked objects and reclaiming space; Because the CMS concurrent cleanup phase user threads are still running, new garbage is naturally generated as the program runs. This part of garbage is generated after the marking process, and the CMS cannot dispose of it in the current collection, so it has to be cleaned up in the next GC. This part of garbage is called “floating garbage”.

A few points to note when using a CMS

Reduce pauses in the Remark phase

Generally, 80% of THE CMS GC time is in the remark phase. If the remark phase has a long pause time, add -xx :+CMSScavengeBeforeRemark. A Young GC is performed before the remark operation to reduce invalid references of the Young generation to the old generation and reduce the overhead of remark.

Memory fragmentation problem

CMS is based on the mark-clear algorithm, CMS will only delete useless objects, does not compress memory, will cause memory fragmentation, we need to use this parameter: – XX: CMSFullGCsBeforeCompaction = n mean in the last time the CMS concurrent GC after the execution, exactly how many times have to perform full GC will do compression. The default is 0, which means that in the default configuration, compression is done every time the CMS GC fails and goes to full GC. If the CMSFullGCsBeforeCompaction configured for 10, you will make the above said the first condition of every 10 times to do a real full GC compression.

concurrent mode failure

This exception occurs while the CMS is collecting. Implementation of the CMS GC, business threads are running at the same time, when the young with space is full, when performing ygc needs will survive object into old age, and at that time, the old s space is insufficient, the CMS haven’t had a chance to recycle old belt, or when doing the Minor GC, new generation rescue space not put, need to put into old age, And the old age also can not put and produced. There are two parameters for setting the trigger time of the CMS:

  • -XX:+UseCMSInitiatingOccupancyOnly
  • -XX:CMSInitiatingOccupancyFraction=70

– XX: CMSInitiatingOccupancyFraction = 70 refers to set the CMS on began to GC in memory usage rate of 70%. – XX: + UseCMSInitiatingOccupancyOnly if not specified, but the recovery by setting threshold CMSInitiatingOccupancyFraction, only used for the first time the JVM Settings, subsequent automatic adjustment will lead to the parameters of the above doesn’t work.

Why do we have these two parameters? Because the user thread in garbage collection phase still need to run, it will also need to set aside enough memory space for user thread is used, therefore the CMS collector can’t wait for old age is almost like other collector is completely filled to be collected, need to set aside part of space to provide operational use concurrent collection program. Five stages before CMS are markers of live objects, in addition to the initial mark “and” to “tag” stage will stop the word, the other three stages are run with user thread, can appear such circumstance gc thread is marked live objects, user threads to raise new objects of old age, at the same time the cleanup has yet to start, Old Gen runs out of room to hold any more objects, which results in a Concurrent mode failure, and the serial collector is used to collect the old garbage, resulting in very long pauses. CMSInitiatingOccupancyFraction parameter to set a reasonable value, set up big, will increase the frequency of concurrent mode failure occurs, set small, and can increase the frequency of CMS, so according to the running situation of the application to select a reasonable value. If this parameter is set too high, it will cause full GC, or too low, it will cause frequent CMS GC. If this parameter is set too low, you should increase the size of the old gc.

promotion failed

During Minor GC, the Survivor Space does not fit, and the object can only be placed in the old age, which is also unable to be placed in the old age. Most of the reason is that the old age has enough free Space, but due to the large number of fragments, the object to be transferred to the old age zone by the new generation is too large, and there is no contiguous area to store the object.

Premature promotion and failure to promote

During a Minor GC, Survivor Unused may not be enough to accommodate Eden and the Survivor in another Survivor, and the surplus will be moved to an older age, Referred to as Premature Promotion, this results in an increase in short-term viability in the old age and may cause serious performance problems. Further, if the old age is Full, the Minor GC is followed by a Full GC, which results in traversing the entire heap, known as Promotion Failure.

Reasons for early promotion

  1. The Survivor space is too small to hold all of the run-time objects with short life cycles. If this is the case, you can try to make Survivor larger; otherwise, the end life objects are promoted too quickly, causing the old age to fill up quickly, leading to frequent full GC.
  2. The objects are too large, and Survivor and Eden do not have enough space to hold these large objects.

Cause of promotion failure

As it ascended, it was found that there was not enough contiguous space in the old age to hold the object. Why is there not enough continuous space instead of free space? There are two cases for objects that cannot be ascended in the old age:

  1. There was not enough free space in the old days;
  2. In the old days, there was a lot of free space, but there was so much fragmentation that there was no contiguous free space to store the object.

The solution

  1. If the promotion of large objects fails due to memory fragmentation, the CMS needs to perform space consolidation and compression.
  2. If the result is caused by too fast promotion, it indicates that the free Survivor space is insufficient. Then, you can try to adjust Survivor.
  3. If it is caused by insufficient space in the old era, try lowering the threshold triggered by the CMS.

CMS Parameters

parameter type The default value instructions
-XX:+UseConcMarkSweepGC boolean false The CMS collector is used in the old era
-XX:+CMSScavengeBeforeRemark boolean false The CMSScavengeBeforeRemark forces scavenge invocation from the CMS-remark phase (from within the VM thread as the CMS-remark operation is executed in the foreground collector).
-XX:+UseCMSCompactAtFullCollection boolean false Compressing older generations eliminates fragmentation, but may incur performance costs
-XX:CMSFullGCsBeforeCompaction=n uintx 0 The CMS performs n full GC and one compression. If n=0, fragmentation is compressed after each full GC. If n=0, fragmentation is compressed after each full GC
– XX: + CMSIncrementalMode boolean false Concurrent collection occurs incrementally, periodically ceding CPU resources to running applications
– XX: + CMSIncrementalPacing boolean false Automatically adjust the number of garbage collection tasks performed each time based on the behavior of the application
– XX: ParallelGCThreads = n uintx (ncpus <= 8) ? ncpus : 3 + ((ncpus * 5) / 8) Number of concurrent reclaim threads
-XX:CMSIncrementalDutyCycleMin=n uintx 0 The minimum percentage of each incremental garbage collection to the total garbage collection task
-XX:CMSIncrementalDutyCycle=n uintx 10 Percentage of each incremental garbage collection to the total garbage collection task
-XX:CMSInitiatingOccupancyFraction=n uintx In JDK6, the default value is 92% When the memory usage reaches N %, reclamation begins.CMSInitiatingOccupancyFraction = (100 - MinHeapFreeRatio) + (CMSTriggerRatio * MinHeapFreeRatio / 100)
-XX:CMSMaxAbortablePrecleanTime=n intx 5000 The maximum amount of time to wait for the Minor GC before the PREclean phase of the CMS begins.

conclusion

  1. The CMS collector only collects old ages, which trade throughput for collection speed.
  2. CMS collection process is divided into initial marking, concurrent marking, pre-cleaning stage, terminable pre-cleaning, re-marking and concurrent cleaning stage. Where initial marking and re-marking are of STW. The CMS spends most of its time in the re-marking phase, so the virtual machine can do a Young GC first to reduce the pause time. CMS cannot solve the floating garbage problem.
  3. Because the CMS has concurrent collection threads and user threads, there may be a “Concurrent mode failure” during the collection process, and the solution is to let the CMS GC as early as possible. Let the CMS compress memory after a certain number of Full GC sessions to reduce memory fragmentation and prevent young objects from failing to be promoted to the old generation due to memory fragmentation.

The resources

Understanding the Java Virtual Machine in Depth – Advanced JVM features and Best Practices – Zhiming Zhou