Daily sentence

Every day costs you more than the day before, because you live another day shorter, so every day you have to pay more attention.

If the profile

One of the most difficult things for a JVM to master is the research and exploration of the GC collection section.For virtual machines, depending on the area and scope and schemeIt can be divided into Minor GC, Major GC and Full GC, etc. Mixed GC is not described here for the time being and will be explored in detail in the following chapters.

The introduction of the GC

The heap memory is divided into Eden, Survivor (2), and Tenured/Old Spaces.

GC that occurs in the young generation — Minor GC

The Minor GC is shown below

  • The virtual machine defines an object Age counter for each object. If an object survives after eden-born and after the first Minor GC and can be accommodated by Survivor, it is moved to Survivor space and the object age is set to 1.

  • Each time an object survives a Minor GC in a Survivor zone, its age increases by one year, and when it reaches a certain age (15 by default), it is promoted to the old age.

  • The age threshold for the object to be promoted to the old age can be set by using -xx :MaxTenuringThreshold.

Collecting memory from young generation Spaces, including Eden and Survivor regions, is known as the Minor GC. This definition is clear and easy to understand, because Java objects are mostly ephemeral, so Minor GC is very frequent and generally fast.

  • The Minor GC is triggered when the JVM is unable to allocate space for a new object, such as when the Eden space is full. So the higher the allocation rate, the more frequently Minor GC is performed.

    • When the pool is full, its contents are copied and the pointer tracks free memory starting at 0.

    • Eden and Survivor zones are marked and copied instead of the classic marked, scanned, compressed, and cleaned operations.

    • So there is no memory fragmentation in Eden and Survivor zones, and the write pointer always stays at the top of the used memory pool.

  • The method area is not affected when Minor GC operations are performed. References from the method area to the young generation are treated as GCRoots, and references from the young generation to the method area are ignored directly during the marking phase.

  • Challenging conventional wisdom, all Minor GCS trigger “stop-the-world”, stopping the application’s threads. For most applications, the delay caused by pauses is negligible.

    • The truth is that most objects in Eden can be considered garbage and will never be copied into Survivor zones or old chronospaces.
  • If the opposite were true and most of the new objects in Eden were not eligible for GC, the pauses in Minor GC would be much longer.

Minor GC trigger mechanism:

A Minor GC is triggered when a young generation is full, which means Eden is full; a Survivor full does not trigger a GC.


GC that happened in the old days — Major GC/Full GC

  • MajorGC: Mainly cleans up old GC: MajorGC is generally 10 times slower than Minor GC

  • Full GC: Mainly cleans the entire heap space – both young and old generations.

    1. First, many Major GC’s are triggered by Minor GC’s, so in many cases it is impossible to separate the two GC’s.
    2. On the other hand, many modern garbage collection mechanisms clean up parts of old chronological space, so using cleaning is only partially correct.

This allows us not to worry about whether the GC is called Major or Full, but whether the current GC stops all application threads or can process concurrently without stopping the application threads.

Old GC (Major GC/Full GC) The application of the Major Collector, often accompanied by at least one Minor GC (but not the absolute, ParallelScavenge avenge).

Full GC trigger mechanism:

  • (1) When system. gc is called, Full GC is recommended, but not necessarily executed
  • (2) Insufficient space in the old era
  • (3) Insufficient Method space: When the permanent generation/metadata space is Full, Full GC will also be triggered, resulting in the unloading of Class and Method meta information.
  • (4) The average size of the old generation after passing the Minor GC is larger than the available memory of the old generation
  • (5) If the size of the object is larger than the available memory of To Space when the Eden or Survivor space1 (From Space) zone is copied To survivor Space2 (To Space) zone, the object is transferred To the old age, and the available memory of the old age is smaller than the size of the object

Full GC is defined as a global GC for the entire new generation, old generation, metaspace (java8 + replaced Perm Gen).

Minor and Major GC are commonly known as Serial GC, Parallel GC, CMS GC, G1 GC and so on.


The first attempt to print from jstat:

my-precious: me$ jstat -gc -t 4235 1s
Copy the code
Time 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 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.720 10.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.810 11.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.896 12.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.978 13.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.091 14.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.233 15.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.386 16.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.484Copy the code

This fragment was extracted 17 seconds after the JVM started. Based on this information, we can conclude that we ran 12 Minor GC and 2 Full GC for a total span of 50 milliseconds.

java -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC eu.plumbr.demo.GarbageProducer

3.157: [Allocation Failure (GC) 3.157: [ParNew: Secs] 272640K->69574K(2063104K), secs] [Times: User =0.23 sys=0.03, real= 0.09secs] 4.092: [GC (Allocation Failure) 4.092: [ParNew: 306688K-> 306688K (306688K), 0.1013723 secs] 342214K->136584K(2063104K), 0.1014307secs] [Times: User =0.25 sys=0.05, real=0.10 secs]... cut for brevity ... 11.292: [Allocation Failure (GC) 11.292: [ParNew: 306686K-> 306688K (306688K), secs] 971599K->779148K(2063104K), secs] [Times: User =0.26 sys=0.04, real=0.09 secs] 12.140: [GC (Allocation Failure) 12.140: [ParNew: 306688K->34046K(306688K), secs] 1051788K->856120K(2063104K), secs] [Times: User =0.25 sys=0.03, real= 0.08secs] 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.11secs] 13.098: [GC (CMS Initial Mark) [1 CMS-initial-mark: [Times: user= 0.03sys =0.00, real=0.00 secs] 13.102: [Times: user= 0.03sys =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.03sys =0.00, real= 0.03secs] 13.350: [cms-concurrent-abortable-preclean-start] 13.878: [Allocation Failure (GC) 13.878: [ParNew: 306688K->34047K(306688K), secs] 1204052K->1010638K(2063104K), secs] [Times: User =0.29 sys=0.04, real= 0.09secs] 14.366: [cmS-concurrent-abortable-preclean: 0.917/1.016secs] [Times: User =2.22 sys=0.07, real= 1.01secs]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: 2. [Class semantics, class semantics, class semantics] 2. [Scrub String table, 0.0003221 secs][1 CMS-remark: 976591K(1756416K)] 1159184K(2063104K), 0.0462010 secs][Times: scrub scrub 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.22secs] 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]Copy the code

Before nodding in agreement with this conclusion, let’s look at the output of the garbage collection log from the same JVM startup collection. Obviously -xx: + PrintGCDetails tells us a different and more detailed story:

Based on this information, we can see that after 12 Minor GC’s, things start to look a little different. Instead of running Full GC twice, the difference is that a single GC runs twice in different phases of the permanent generation:

The initial tagging phase took 0.0041705 seconds or about 4ms. This phase pauses the “stop-the-world” event, stops all application threads, and then begins marking.

The marking and cleaning phases are performed in parallel. These are parallel to the application threads. In the final Remark phase, 0.0462010 seconds were spent about 46ms. This phase suspends all events again. 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’s actually just a Major GC to clean up the old chronospace, not a Full GC twice.