A simple case, take you to understand GC log!

code

public class Main {
 
  public static void main(String[] args) {
    byte[] array1 = new byte[4 * 1024 * 1024];
    array1 = null;
 
    byte[] array2 = new byte[2 * 1024 * 1024];
    byte[] array3 = new byte[2 * 1024 * 1024];
    byte[] array4 = new byte[2 * 1024 * 1024];
    byte[] array5 = new byte[128 * 1024];
    byte[] array6 = new byte[2 * 1024 * 1024];
  }
}

parameter

Parameter setting operation

-XX:NewSize=10M -XX:MaxNewSize=10M -XX:InitialHeapSize=20M -XX:MaxHeapSize=20M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:PretenureSizeThreshold=3M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log

Parameter introduction

-XX:NewSize:Initial young generation size
-XX:MaxNewSize:Maximum younger generation size
-XX:InitialHeapSize:Defines the initialization size of the heap. The default value is 1 of the physical memory/64,Actually:-Xms
-XX:MaxHeapSize:Defines the maximum heap size, which defaults to 1 of physical memory/4,Actually:-Xmx
-XX:SurvivorRatio:Eden District and Survivor Area size ratio
-XX:MaxTenuringThreshold:Maximum age value of objects from younger generation to older generation
-XX:PretenureSizeThreshold=3M:Object size exceeds 3 M Allocate memory directly in the older generation
-XX:+UseParNewGC:use ParNew collector
-XX:+UseConcMarkSweepGC:use CMS collector
-XX:+PrintGCDetails:GC Print details when
-Xloggc:output GC Log information to file

journal

Log condition

0.095: [GC (Allocation Failure) 0.095: [ParNew (promotion failed): 7838K->8391K(9216K), 0.0029438 secs]0.098: [CMS: 8194K->6659K(10240K), 0.0024311 secs] 11934K->6659K(19456K), [Metaspace: 3121K->3121K(1056768K)], 0.0055393 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
Heap
 par new generation   total 9216K, used 2214K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,  27% used [0x00000007bec00000, 0x00000007bee29820, 0x00000007bf400000)
  from space 1024K,   0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
  to   space 1024K,   0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
 concurrent mark-sweep generation total 10240K, used 6659K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 3142K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 347K, capacity 388K, committed 512K, reserved 1048576K

Log explanation

GC: Indicates that a garbage collection has been performed, and there is no previous garbage collection Full Modification, indicating that this is a Young GC

Allocation Failure: It indicates that this caused GC The reason is that there is not enough space in the younger generation to store new data

ParNew: Indicates that this GC Occurs in the younger generation and uses ParNew Garbage collector. ParNew It's a Serial The multithreaded version of the collector, which uses multiple CPU And threads complete garbage collection (number of threads used by default and CPU The same number can be used-XX: ParallelGCThreads Parameter limit)

ParNew (promotion failed): 7838K->8391K(9216K) 7838K->8391K(9216K): Unit is KB,The three parameters are: GC This memory area before(This is the young generation)Capacity used, GC The used capacity of the memory area and the total capacity of the memory area.

0.0029438 secs: This memory area GC Time, in seconds

CMS: 8194K->6659K(10240K), 0.0024311 secs] 11934K->6659K(19456K)  8194K->6659K(10240K): GC This memory area before(This is the old age)Usage capacity change, 10240 K Represents the total capacity of the memory area, 11934 K->6659K(19456K): The three parameters are: the size of the heap before garbage collection, the size of the heap after garbage collection, and the total size of the heap

Times: user=0.02 sys=0.00, real=0.00 secs: Represents user mode time, kernel mode time and total time respectively

Detailed introduction

You can see that promotion failed occurs. Under what circumstances will promotion failed occur?

When performing Young GC, the Survivor Space cannot be put down, and the object can only be put into the elderly generation, which will appear when the elderly generation cannot be put down

1. Look at the code

byte[] array1 = new byte[4 * 1024 * 1024];
array1 = null;

This line of code directly allocates a 4MB large object. At this time, the object will directly enter the old generation, and then array1 will no longer reference this object

2. Then look at the following code

byte[] array2 = new byte[2 * 1024 * 1024];
byte[] array3 = new byte[2 * 1024 * 1024];
byte[] array4 = new byte[2 * 1024 * 1024];
byte[] array5 = new byte[128 * 1024];

Four arrays are allocated consecutively, three of which are 2MB arrays and one is 128KB array, as shown in the figure below. All of them will enter the Eden area

3. The following code will be executed:

byte[] array6 = new byte[2 * 1024 * 1024];

Can I still hold 2MB of objects at this time? It's impossible because Eden district can't let go. Therefore, a Young GC will be triggered directly at this time.

4. Let's look at the following GC logs:

ParNew (promotion failed): 7838K->8391K(9216K), 0.0029438 secs

This log shows that there were nearly 8000KB objects in Eden area, but after recycling, it was found that none of them could be recycled. Because the above arrays are referenced by variables, these surviving objects will be directly put into the old age, but there is already a 4MB array in the old age, Can you still put 3 2MB arrays and 1 128KB array?

Obviously not. At this time, it will exceed the 10MB size of the old age.

5. So let's look at the gc log of cms:

CMS: 8194K->6659K(10240K), 0.0024311 secs] 11934K->6659K(19456K), [Metaspace: 3121K->3121K(1056768K)], 0.0055393 secs

You can clearly see that the Full GC of CMS garbage collector is executed at this time. We know that the Full GC is actually an Old GC for the elderly generation. At the same time, it is generally associated with a Young GC and triggers a GC in the metadata area (permanent generation).

The Young GC was triggered before CMS Full GC. At this time, you can see that the Young GC already exists, and then the Old GC for the elderly generation is executed, that is, the following log:

CMS: 8194K->6659K(10240K), 0.0024311 secs

6. Here we can see that in the old age, the object occupation has changed from about 8MB to about 6MB. What is the process?

It's very simple. After the Young GC, first put two 2MB arrays into the old age. At this time, continue to put one 2MB array and one 128KB array into the old age. It will not be put down until the old age, so the Full GC of CMS will be triggered at this time

Then, one of the 4MB arrays will be recycled because it is no longer referenced

Then put in a 2MB array and a 128KB array

So let's look at the garbage collection log of CMS: CMS: 8194k - > 6659k (10240k), 0.0024311 secs, which has changed from 8MB before recycling to 6MB

Finally, after CMS Full GC is executed, in fact, the objects of the younger generation have entered the old age. At this time, the last line of code needs to allocate 2MB array in the younger generation

Supplementary knowledge

Young GC trigger condition

Young GC will be triggered once when the young generation Eden area is full

Full GC trigger condition

Full GC is used to clean up the entire heap space. Its triggering conditions mainly include the following:

1. Explicitly call system GC method (JVM trigger recommended).

2. Insufficient meta space

3. Insufficient space caused Full GC. This situation is complex, including the following:

  • Large objects directly enter the old generation, which is defined by the - XX:PretenureSizeThreshold parameter
  • When Young GC, objects that have experienced many times and still exist in Young GC enter the elderly generation.
  • In Young GC, the dynamic object age determination mechanism will transfer the object to the old age in advance. The age is accumulated from small to large. When a certain age group is added and the accumulation exceeds the survivor area - XX:TargetSurvivorRatio, the objects with an upward age from this age group enter the elderly generation
  • In Young GC, when the Eden and From Space areas are copied to the To Space area, they are larger than the available memory of the To Space area, and the objects will be directly transferred to the old age

4. The JVM's space allocation guarantee mechanism may trigger Full GC:

Space guarantee allocation means that before the occurrence of Young GC, the virtual opportunity checks whether the maximum available continuous space of the elderly generation is greater than the total space of all objects of the new generation.

If greater than, the Young GC is safe this time.

If less than, the virtual opportunity checks whether the HandlePromotionFailure setting allows guarantee failure.

If HandlePromotionFailure=true, it will continue to check whether the maximum available continuous space of the elderly generation is greater than the average size of objects promoted to the old age. If it is greater than, it will try a Young GC, but this Young GC is still risky. After failure, it will restart a full GC; If it is less than or HandlePromotionFailure=false, a full GC will be performed directly instead.

GC Easy tool

Here is a gceasy( https://gceasy.io )Tool, you can upload GC files, and then it will use the visual interface to show the GC situation

reference resources

https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html

https://book.douban.com/subject/34907497/

This paper consists of Pony Creation, adoption Knowledge sharing attribution 4.0 License under international license agreement Except for the reprint / source, all articles on this site are original or translated by this site. Please sign your name before reprinting Last edited at: 11:25, December 19, 2021

Added by vulcant13 on Mon, 20 Dec 2021 13:48:24 +0200