Deep understanding of the JVM-CMS collector
preface
In the last section, we looked at generational and garbage collection algorithms. In this section, we’ll look at an important garbage collector from the past: the CMS collector. Again, this section is quite informative.
This section focuses on the very common CMS garbage collector.
These reviews
In the last article, we explained the basic theory of generation, while explaining the new generation and the old generation of their respective algorithm replication algorithm and mark sorting algorithm, and then we summarized the conditions of the new generation into the old age, in the end we introduced the type of citation, and at the same time conducted the exercise of questions and related answers.
An overview of the
- Before I talk about the CMS collector, take a brief look at his golden partner, Parnew
- Explains the parameters of the CMS collector, as well as the core running steps section.
- Explains the details of how the CMS collector runs and what the parameters of the CMS mean.
- Collect a small number of common JVM problems
Golden partner Parnew
The most commonly used new generation garbage collector, Parnew, is paired with the CMS collector, which was the official JDK recommendation prior to JDK 1.9 and is currently the most commonly used collector combination.
The ParNew collector itself is a multithreaded version of the Serial collector. The Serial Collector and Serial Old Collector are too Old to be covered here, but it is not to say that they are obsolete. The key role of the Serial Collector will be mentioned later in this article.
Finally, note that Parnew is the only garbage collector other than Serial that works with CMS
Features:
- Serrial is the difference between single-threaded and multi-threaded
- The only garbage collector other than Serrial that works with CMS
Question Answer:
Which is a good multi-threaded collector or a single-threaded collector?
In general, multithreaded collectors are preferred for servers, while single-threaded collectors are preferred for clients. If a single-core machine uses multiple threads, there will be additional “context switching” operations, and performance will not improve, but will decrease. At the same time, the client in most cases is not very high requirements for multi-threading, so the client is more recommended to use a single thread.
Serial is better than ParNew, which collector?
As with the above question, this depends on whether the machine you are using is multi-core or single-core. Of course, in most cases, multithreading will be used, because the multithreading technology of modern processors is quite mature.
Analysis:
In the client mode, -client represents the parameters required by the client and -server represents the operational parameters required by the server.
Server-side pattern: Usually suitable for multi-core environments, such as Parnew, which is highly utilized for multi-threaded garbage collection.
Client mode: Suitable for machines with poor performance on a single core, since it usually runs on a single core, and for the Serial collector, since it is single-threaded and has no overhead of thread switching
CMS collector
The most commonly used garbage collector in the old days before JDK9, mainly uses mark-sweep algorithms (not entirely mark-sweep algorithms). In order to ensure the efficiency of operation, the CMS adopts the way of concurrent execution of the user thread and the garbage collector thread. It is also the first garbage collector to support concurrent execution of the user thread and the garbage collector thread.
As discussed in a previous article, tag purge algorithms generate a lot of memory fragmentation, so why use mark-purge algorithms?
CMS determines, based on a system parameter, how many times the garbage collection is followed by a defragment action that stops all current user threads and starts the single-threaded Serial collector to defragment old memory. This defragment is the tag – defragment used.
But in general, CMS uses the mark-clear action.
CMS collector features:
- Can not be used alone, will need to work with other collectors and will only work with Serrial and Parnew collectors
- In order to ensure the efficiency of the operation, the CMS will use the concurrent execution of the user thread and the garbage collection thread. It was also the first garbage collector to support concurrent user and garbage collection threads
- Mark-sweep based algorithm.
- A garbage collector that focuses on the shortest pause times
Main parameters of CMS:
- -XX:ParallelGCThreads: limit the number of garbage collection threads by default to (total number of CPU cores + 3) / 4, such as 2 garbage collection threads for 8 cores
- + USECMS-CompactAtFullCollection (JDK9 enabled deprecated) : When enabled, run the fragment operation after each FULLGC and clean up the memory, which needs to stop the user thread. Increases the duration of Stop the World
- -XX: CMSFULLGCSBEFORE -COMPACTION (JDK9 enabled deprecated) : + usecms-compactAtFullCollection (fullGC) : * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- – XX: CmsInitiatingOccupancyFranction: used to limit the old s memory footprint after more than how much of the action to garbage collection. It was 68% for JDK5 and 92% after JDK6.
Running steps of CMS (key points)
The four recovery steps of CMS are easy to understand. They are mainly four steps:
- Initial markup: This process is very fast, requiring you to stop the world, traverse all objects, and mark the initial GC root
- Concurrent tags: this process can be done concurrently with user threads, so for the system process is small, the influence of the main work is in the system when thread running through the gc root root node enumeration for object operation, tag object is alive, note the tag is also more rapid and simple, for the next step is need to mark
- Relabelling: You need to stop the world. This phase will continue to complete the actions of the previous phase. The object marked in the previous step will be traversed a second time to re-mark whether it is alive or not.
- Concurrent cleanup: Concurrent with the user thread, responsible for collecting garbage objects that do not have a GC Root reference.
Describe the steps above you can see, CMS has had the very big progress, garbage collector can implement concurrent tags and subsequent finishing stage and the user threads execute concurrently (but more system resources), don’t interfere with the user thread object allocation operations, but need to pay attention to the initial tag and mark phase still need pause again.
Initial tag
The initial marking phase: You need to pause the user thread and start the garbage collection thread, but just collecting the current vintage GC Root object, the whole process runs so fast that the user is barely aware of it.
The important thing to note here is which objects are treated as GC Root and which are not, such as instance variables that are not GC Root objects, and the ROOT node enumeration is marked as garbage if it is not referenced.
Which nodes can act as GC root
- Local variables themselves can act as GC ROOT
- Static variables can be thought of as GC Root
- The traversal loop for a Long index is treated as GT ROOT
Conclusion: when there is a method local variable reference or a class static variable reference, it will not be collected by the garbage thread.
Concurrent tags
Concurrent marking phase: Can execute concurrently with user threads, the system process will continue to allocate objects in a virtual machine, and garbage collection threads will be according to the gc root for the old s validity tests object, the object tag as live objects or garbage objects, this stage is the most time consuming, but due to the concurrent execution and the user thread, the effect is not very big.
Note that this phase does not complete the marking of objects that need to be garbage collected, because there may be live objects that become garbage objects at this point, and garbage objects may also become live objects.
Supplement – The difference between concurrency and parallelism in a JVM:
Parallelism: Refers to the relationship between multiple garbage collection threads
Concurrency: The relationship between the garbage collector and the user thread
To mark
Relabelling stage: this stage also needs to stop world, which will continue to complete the actions of the previous stage. In fact, it is to mark and judge the survival of objects already marked in the second stage again. This process is very fast, because it is the finishing work of the previous step.
Concurrent cleaning
Concurrent cleanup phase: This phase is also run concurrently with the user thread, so the user thread can continue to allocate objects while the garbage collector thread performs garbage collection. This phase is also time-consuming, but the effect is not significant because it is run concurrently.
What problems the CMS collector causes
Thread resource occupied by garbage collection thread (CPU resource utilization problem)
Because concurrent marking and concurrent cleaning are the two stages that need to be concurrent with the user thread, at this time, it needs to occupy a part of the entire system’s resources, which are left to the garbage thread for concurrent processing.
Another obvious problem here is that in a single-core, single-threaded system, preemptive multitasking is used internally by the CMS to simulate multi-core parallelism, and incremental collectors are turned on for threaded processing. However, this collector I-CMS was not very effective and was deprecated in JDK 7, and has been completely removed in JDK 9.
Single-core, single-threaded machines need to be carefully considered for the use of CMS.
Concurrent Mode Fail
CMS is a hard-working young man who works in an orderly manner on garbage collection. But when too much garbage becomes too much for the young man to handle, Serrial, the older man watching behind, shouts: Stop the world and do a quick garbage collection. Get the job done and retire to the background. Let the guy get back to work.
Of course, the above case is not personal creation, personal learning when I saw a very vivid metaphor, of course, we can not explain so when we explain, this is not a professional should say.
When the user thread runs concurrently with the garbage collector thread, the garbage collector thread will allocate more memory than the garbage collector thread. If the garbage thread and the garbage collector thread run concurrently, the garbage collector thread will allocate more memory than the garbage collector thread and cause OOM problem. So before CMS will default according to the introduction of the CMS parameters – xx: specifies how old s memory footprint after cmsInitiatingOccupactAtFullCollection for garbage collection.
In the Jdk – xx: cmsInitiatingOccupactAtFullCollection parameters in jdk5 is 68%, while jdk6 has adjusted to 92%.
Another problem is that during the Concurrent cleanup phase, if the user thread allocates more objects than the remaining memory (say, the last 8% of the space) and the garbage collector thread is still working, then a Concurrent Mode Fail issue will occur. At this point, Stop World immediately pauses the user process and starts the Serial collector for garbage collection cleanup. When the garbage collection is complete, the user user thread is started and the work of the CMS collector resumes.
This ratio should be carefully adjusted in the actual use process to prevent concurrent failure.
You can see the Serial collector as a bottom-up operation, and one might wonder why we use a single-threaded garbage collector like Serial instead of other garbage collectors.
Just like Redis, single thread does not necessarily mean poor performance, nor does multi-threading mean good performance. Serial, as an old garbage collector, is simple to implement, but it has an advantage that other collectors do not have, namely high efficiency and good performance. This is why Serial is used as a backstop rather than another garbage collector.
Memory fragments
This problem is due to the CMS using the tag itself – clear algorithm implementation, concurrent tags and concurrent cleanup phase are for direct marking, and recycling of waste objects, in mark phase is only for gc root has labeled objects to make a judgement, all the process won’t produce the movement of the object operation, This causes memory objects to be clump together, and if a new generation of large objects comes in at this time, it can easily result in frequent Full GC.
The official solution is to perform a “mark-tidy” action on memory at the end of each tag collation, which also requires “Stop World” to pause the user thread, move the living objects into one place, and clean up all the garbage objects.
The JDK provides the: -XX: CMSFULLGCbefore-COMPACTION parameter to specify how many times a full GC will perform a collation. The default is 0, which means that a collation will be performed each time.
Question sorting:
What are The Times to trigger vintage recycling?
This point has been mentioned many times before, but I’ll mention it again, along with the addition of an opportunity to trigger an old Full GC when using the CMS collector.
- The usable continuous space of the old age is smaller than the size of all objects in the new age
- The available continuous space of the old age is smaller than the mean size of the Cenozoic age
- Minor GC of new memory cannot enter the Survior field, while space of old memory is insufficient
- – xx: cmsInitiatingOccupactAtFullCollection in Cms under the condition of the garbage collector, if concurrent cleanup phase space the size of the object is assigned to more than 8% of the final size, will trigger the concurrent Fail results in failure.
Question: Why is the recycling speed of the old generation so much slower than the new generation?
- First of all, there were a lot of memory objects in the old days, the GC ROOT was very slow, and the garbage collection time was extended.
- The marking-collation algorithm needs to move a large number of objects to one place after cleaning, and also needs to update cross-generation references and reference addresses of objects, etc., which takes a long time. In the new generation of replication algorithm, objects are relatively small at the same time. The algorithm directly copies the surviving objects and then clears the Eden area, leaving few objects to enter the old age.
- If the tag – cleaning algorithm is used, it will cause fragmentation of memory. If there are too many fragments, the thread needs to be stopped for shuffling and sorting.
This thinking problem mainly starts from two aspects of the algorithm and the number of objects. The time overhead required by the new generation copy algorithm is different from that of the old mark-collate algorithm. At the same time, the old generation itself has too many objects, and combined with the feature that the JVM mainly uses root node enumeration, it will inevitably lead to the pause and wait of the user thread. Even though the latest generation of collectors (ZGC and Shenadash) can do almost complete concurrency with the user thread, there is a need to pause the user thread during the root node enumeration step. As you can see, the old age collection is slow and we need to avoid the old age triggering garbage collection.
The “useless classes” (method area) that GC collects:
The method area collection criteria are re-emphasized here:
1. All instances of the class have been collected, that is, there are no instances of the class in the Java heap
2. The ClassLoader that loaded this class has been reclaimed
3. The java.lang.Class object corresponding to this Class is not referenced anywhere, and the method of this Class cannot be accessed by reflection anywhere
From https://www.cnblogs.com/erma0…
Write in the last
Garbage collector is a lot of detail, so this is a long article, but the CMS garbage collector is an important and noteworthy collector.
It can be seen from this section that the recycling of old age has great side effects on CMS, so the next section will explain some ideas to avoid the recycling of old age according to a simulated case.