An article thoroughly clarifies the relationship between Minor GC, Major GC, and Full GC!

Preface

The article requires readers to be familiar with the general garbage collection principles built into the JVM. The heap memory is divided into Eden, Survivor, and Tenured/Old spaces. The hypothesis and other different GC algorithms are beyond the scope of this article.
Insert picture description here

Minor GC

Reclaiming memory from the young generation space (including the Eden and Survivor areas) is called Minor GC. This definition is clear and easy to understand. However, when a Minor GC event occurs, there are some interesting things to note:

1. Minor GC will be triggered when the JVM cannot allocate space for a new object, such as when the Eden area is full. Therefore, the higher the allocation rate, the more frequently the Minor GC is executed.

2. When the memory pool is full, all its contents will be copied, and the pointer will start tracking free memory from 0. Eden and Survivor areas are marked and copied, replacing the classic marking, scanning, compressing, and cleaning operations. Therefore, there is no memory fragmentation in Eden and Survivor areas. The write pointer always stays at the top of the memory pool used.

3. When the Minor GC operation is executed, the permanent generation will not be affected. References from the permanent generation to the young generation are regarded as GC roots, and references from the young generation to the permanent generation are directly ignored in the marking phase.

4. Question conventional perceptions. All Minor GCs will trigger "stop-the-world" to stop the application thread. For most applications, the delay caused by the pause is negligible. The truth is that most of the objects in the Eden area can be considered garbage and will never be copied to the Survivor area or the old space. If it is the opposite, most of the new objects in the Eden area do not meet the GC conditions, and the pause time during the execution of the Minor GC will be much longer.

So the situation of Minor GC is quite clear-every time Minor GC will clean up the memory of the young generation.

Major GC vs Full GC

You should note that at present, these terms are not officially defined in either the JVM specification or in garbage collection research papers. But we know at a glance that these definitions made on the basis of what we already know are correct, and the Minor GC cleaning the young belt memory should be designed to be simple:

  • Major GC is to clean up the old generation.
  • Full GC is to clean up the entire heap space-including the young generation and the old generation.

Unfortunately, it is actually a bit complicated and confusing. First of all, many Major GCs are triggered by Minor GCs, so in many cases it is impossible to separate these two GCs. On the other hand, many modern garbage collection mechanisms clean up part of the permanent generation space, so the term "cleaning" is only partially correct.

This saves us from worrying about whether it is called Major GC or Full GC. You should pay attention to whether the current GC stops all application threads or whether it can process concurrently without stopping the application threads.

This confusion is even built into JVM standard tools. The following example explains what I mean very well. Let us compare the trace records output by two different tools, Concurrent Mark and Sweep collector (-XX:+UseConcMarkSweepGC) when they run in the JVM.

The first attempt to output through jstat:

my-precious: me$ jstat -gc -t 4235 1sTime S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT    5.7 34048.0 34048.0  0.0   34048.0 272640.0 194699.7 1756416.0   181419.9  18304.0 17865.1 2688.0 2497.6      3    0.275   0      0.000    0.275 6.7 34048.0 34048.0 34048.0  0.0   272640.0 247555.4 1756416.0   263447.9  18816.0 18123.3 2688.0 2523.1      4    0.359   0      0.000    0.359 7.7 34048.0 34048.0  0.0   34048.0 272640.0 257729.3 1756416.0   345109.8  19072.0 18396.6 2688.0 2550.3      5    0.451   0      0.000    0.451 8.7 34048.0 34048.0 34048.0 34048.0 272640.0 272640.0 1756416.0  444982.5  19456.0 18681.3 2816.0 2575.8      7    0.550   0      0.000    0.550 9.7 34048.0 34048.0 34046.7  0.0   272640.0 16777.0  1756416.0   587906.3  20096.0 19235.1 2944.0 2631.8      8    0.720   0      0.000    0.72010.7 34048.0 34048.0  0.0   34046.2 272640.0 80171.6  1756416.0   664913.4  20352.0 19495.9 2944.0 2657.4      9    0.810   0      0.000    0.81011.7 34048.0 34048.0 34048.0  0.0   272640.0 129480.8 1756416.0   745100.2  20608.0 19704.5 2944.0 2678.4     10    0.896   0      0.000    0.89612.7 34048.0 34048.0  0.0   34046.6 272640.0 164070.7 1756416.0   822073.7  20992.0 19937.1 3072.0 2702.8     11    0.978   0      0.000    0.97813.7 34048.0 34048.0 34048.0  0.0   272640.0 211949.9 1756416.0   897364.4  21248.0 20179.6 3072.0 2728.1     12    1.087   1      0.004    1.09114.7 34048.0 34048.0  0.0   34047.1 272640.0 245801.5 1756416.0   597362.6  21504.0 20390.6 3072.0 2750.3     13    1.183   2      0.050    1.23315.7 34048.0 34048.0  0.0   34048.0 272640.0 21474.1  1756416.0   757347.0  22012.0 20792.0 3200.0 2791.0     15    1.336   2      0.050    1.38616.7 34048.0 34048.0 34047.0  0.0   272640.0 48378.0  1756416.0   838594.4  22268.0 21003.5 3200.0 2813.2     16    1.433   2      0.050    1.484

This snippet was extracted at the 17th second after the JVM started. Based on this information, we can come to this result, running 12 Minor GC and 2 Full GC, with a total time span of 50 milliseconds. You can get the same result with GUI-based tools like jconsole or jvisualvm.

java -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC eu.plumbr.demo.GarbageProducer3.157: [GC (Allocation Failure) 3.157: [ParNew: 272640K->34048K(306688K), 0.0844702 secs] 272640K->69574K(2063104K), 0.0845560 secs] [Times: user=0.23 sys=0.03, real=0.09 secs] 4.092: [GC (Allocation Failure) 4.092: [ParNew: 306688K->34048K(306688K), 0.1013723 secs] 342214K->136584K(2063104K), 0.1014307 secs] [Times: user=0.25 sys=0.05, real=0.10 secs] ... cut for brevity ...11.292: [GC (Allocation Failure) 11.292: [ParNew: 306686K->34048K(306688K), 0.0857219 secs] 971599K->779148K(2063104K), 0.0857875 secs] [Times: user=0.26 sys=0.04, real=0.09 secs] 12.140: [GC (Allocation Failure) 12.140: [ParNew: 306688K->34046K(306688K), 0.0821774 secs] 1051788K->856120K(2063104K), 0.0822400 secs] [Times: user=0.25 sys=0.03, real=0.08 secs] 12.989: [GC (Allocation Failure) 12.989: [ParNew: 306686K->34048K(306688K), 0.1086667 secs] 1128760K->931412K(2063104K), 0.1087416 secs] [Times: user=0.24 sys=0.04, real=0.11 secs] 13.098: [GC (CMS Initial Mark) [1 CMS-initial-mark: 897364K(1756416K)] 936667K(2063104K), 0.0041705 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 13.102: [CMS-concurrent-mark-start]13.341: [CMS-concurrent-mark: 0.238/0.238 secs] [Times: user=0.36 sys=0.01, real=0.24 secs] 13.341: [CMS-concurrent-preclean-start]13.350: [CMS-concurrent-preclean: 0.009/0.009 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 13.350: [CMS-concurrent-abortable-preclean-start]13.878: [GC (Allocation Failure) 13.878: [ParNew: 306688K->34047K(306688K), 0.0960456 secs] 1204052K->1010638K(2063104K), 0.0961542 secs] [Times: user=0.29 sys=0.04, real=0.09 secs] 14.366: [CMS-concurrent-abortable-preclean: 0.917/1.016 secs] [Times: user=2.22 sys=0.07, real=1.01 secs] 14.366: [GC (CMS Final Remark) [YG occupancy: 182593 K (306688 K)]14.366: [Rescan (parallel) , 0.0291598 secs]14.395: [weak refs processing, 0.0000232 secs]14.395: [class unloading, 0.0117661 secs]14.407: [scrub symbol table, 0.0015323 secs]14.409: [scrub string table, 0.0003221 secs][1 CMS-remark: 976591K(1756416K)] 1159184K(2063104K), 0.0462010 secs] [Times: user=0.14 sys=0.00, real=0.05 secs] 14.412: [CMS-concurrent-sweep-start]14.633: [CMS-concurrent-sweep: 0.221/0.221 secs] [Times: user=0.37 sys=0.00, real=0.22 secs] 14.633: [CMS-concurrent-reset-start]14.636: [CMS-concurrent-reset: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

Before nodding to agree with this conclusion, let's take a look at the output of garbage collection logs from the same JVM that started the collection. Obviously-XX: + PrintGCDetails tells us a different and more detailed story:

Based on this information, we can see that after 12 Minor GCs, it is somewhat different from the above. The Full GC did not run twice. The difference is that a single GC runs twice in different stages in the permanent generation:

1. The initial marking phase took 0.0041705 seconds, which is about 4ms. This stage will pause the "stop-the-world" event, stop all application threads, and start marking.

2. The marking and cleaning phases are executed in parallel. These are parallel to the application threads.

3. The final Remark phase took 0.0462010 seconds and about 46ms. All events will be suspended again at this stage.

4. Perform cleanup operations in parallel. As the name suggests, this phase is also parallel and does not stop other threads.

So, as we can see from the garbage collection log, it is actually only a Major GC to clean up the space of the old generation, instead of two Full GCs.

If you are making a decision later, then the data provided by jstat will guide you to make the right decision. It correctly listed the two cases of suspending all events, causing all threads to stop for a total of 50ms. But if you try to optimize throughput, you will be misled. The list only lists the initial mark and final Remark stages of recycling, and the output of jstat does not see those concurrently completed work.

in conclusion

Considering this situation, it is best to avoid thinking about problems in such a way as Minor, Major, and Full GC. Instead, monitor application latency or throughput, and then correlate GC events with results.
As these GC events occur, you need to pay extra attention to certain information. Whether the GC event forces all application threads to stop or processes some events in parallel.

At last

Provide free Java architecture learning materials, learning technology content includes: Spring, Dubbo, MyBatis, RPC, source code analysis, high concurrency, high performance, distributed, performance optimization, microservice advanced architecture development, etc.

Friends in need can click: click this! Click this! , Code: csdn.

There are also Java core knowledge points + a full set of architect learning materials and videos + first-line interview books + interview resume templates can be obtained + Ali Meituan Netease Tencent Xiaomi Iqiyi Kuaishou Bilibili interview questions + Spring source code collection + Java architecture Practical e-book + 2020 latest interview questions from major manufacturers.
Insert picture description here
Insert picture description here

Guess you like

Origin blog.csdn.net/HarderXin/article/details/109334145