Environment to prepare
Such a case procedure:
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]; }}Copy the code
We run the program with the following parameters:
❝
-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 Description:
-xx :NewSize: initial young generation size -xx :MaxNewSize: maximum young generation size -xx :InitialHeapSize: defines the initial size of the heap. The default value is 1/64 of physical memory. -xms -xx :MaxHeapSize: defines the maximum heap size, default is 1/4 of the physical memory, -xmx-xx :SurvivorRatio: SurvivorRatio of Eden zones to Survivor zones -xx :MaxTenuringThreshold: maximum age of a younger generation object to be converted to an older generation object - XX: PretenureSizeThreshold = 3 m: object size exceeds 3 m directly allocates memory in old s - XX: + UseParNewGC: use ParNew collector - XX: + UseConcMarkSweepGC: use CMS collector -xx :+PrintGCDetails: prints details during GC. -xloggc: prints GC logs to a fileCopy the code
GC logs printed:
[ParNew (Promotion failed): 8143K->8713K(9216K), 0.0043061 secs]0.122: [CMS: 12239K->6675K(19456K), [Metaspace: 3042 k - > 3042 k (1056768 k)], 0.0082981 secs] [Times: User =0.03 sys=0.01, real=0.01 SECS] Heap PAR new generation Total 9216K, used 2213K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000) eden space 8192K, 27% used [0x00000007bec00000, 0x00000007bee297c8, 0x00000007bf400000) from space 1024K, 0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000) to space 1024K, 0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000) concurrent mark-sweep generation total 10240K, used 6675K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000) Metaspace used 3063K, capacity 4496K, committed 4864K, reserved 1056768K class space used 334K, capacity 388K, committed 512K, reserved 1048576KCopy the code
Log details:
GC: Indicates that a garbage collection has taken place, without the Full modifier, indicating that this is a Young GC
Allocation Failure: Indicates that the GC is caused because there is not enough space in the young generation to store new data
ParNew: Indicates that the GC is in the young generation and the ParNew garbage collector is used. ParNew is a multithreaded version of the Serial collector that uses multiple cpus and threads for garbage collection (the default number of threads is the same as the number of cpus, so you can use the -xx: ParallelGCThreads parameter limit).
ParNew (promotion failed): 8143K->8713K(9216K) : the unit is KB. The three parameters are as follows: Used capacity of the memory region before GC, used capacity of the memory region after GC, and total capacity of the memory region.
0.0043061 secS: Indicates the GC duration of the memory area, in seconds
CMS: Secs] 12239K->6675K(19456K)8194K->6675K(10240K) : 10240K indicates the total capacity of the memory region. 12239K->6675K(19456K) : three parameters are respectively: 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.03 sys=0.01, real=0.01 secS: indicates the user time, kernel time, and total time respectively
At the same time, it can be seen that promotion failed appears. Under what circumstances will promotion failed appear?
Understand JVM, GC algorithms, and performance tuning
❝
During a Young GC, Survivor Spaces are not available, and objects can only be placed in older ages, which are also unavailable
❞
Detailed introduction
“Let’s talk more about the GC process:”
First let’s look at the following code:
byte[] array1 = new byte[4 * 1024 * 1024];
array1 = null;
Copy the code
This line of code directly allocates a large 4MB object, at which point the object goes straight to the old age, and Array1 no longer references the object
Now 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];
Copy the code
Four arrays are allocated consecutively, among which three are 2MB and one is 128KB, as shown in the figure below. All of them will enter Eden area
The following code is then executed:
byte[] array6 = new byte[2 * 1024 * 1024];
Copy the code
Is there room for 2MB objects at this point? That’s impossible, because there’s no room in Eden anymore. So a Young GC is fired directly at this point.
Let’s look at the following GC log:
❝
ParNew (promotion failed): 8143K->8713K(9216K), 0.0043061 secs
❞
This log shows that the Eden area originally has more than 8000 KB of objects, but after the retrieval, it is found that none of the objects can be reclaimed, because the above arrays are referenced by variables 1, so it must be directly put these surviving objects into the old age, but now there is already a 4MB array in the old age. Is there room for three 2MB arrays and one 128KB array?
Obviously not, at this time will exceed the old 10MB size.
So let’s look at the CMS gc log at this point:
❝
CMS: 8194K->6675K(10240K), 0.0038347 secS [Metaspace: 3042K->3042K(1056768K)], 0.0082981 secs
❞
As you can clearly see, the CMS garbage collector’s Full GC is actually an Old GC, which is associated with a Young GC and triggers a metadata section (permanent generation).
Before the CMS Full GC, the Young GC has been triggered, so you can see that the Young GC already exists, and then the Old GC for the Old generation is executed.
❝
CMS: 8194 k – > 6675 k (10240 k), 0.0038347 secs]
❞
“Here we see that the old age has gone from around 8MB of object occupancy to around 6MB of object occupancy. How does this happen?”
The CMS Full GC is triggered when the Young GC is loaded with 2 arrays (2MB) and 1 array (128KB). The Young GC is loaded with 2 arrays (128KB)
It then recycles one of the 4MB arrays because it is no longer referenced
We then put in a 2MB array and a 128KB array
CMS: 8194K->6836K(10240K), 0.0049920 secs, it changed from 8MB to 6MB
Finally, after the CMS Full GC is complete, the objects of the young generation are in the old age, and the last line of code allocates the 2MB array of the young generation successfully
Supplement knowledge
To facilitate the understanding of the above, add the following knowledge
“Young GC trigger condition:”
A Young GC is triggered when the Eden region of the Young generation is full
“Full GC trigger condition:”
The Full GC is used to clean up the entire heap space. Its trigger conditions are mainly as follows:
1. Call the System.gc method explicitly (JVM trigger is recommended).
2. The meta space is insufficient
3. Insufficient chronospace causes Full GC. This situation is more complex, there are the following:
-
Large object directly into old age, by – XX: PretenureSizeThreshold parameter definition
-
When the Young GC is used, objects that have survived the Young GC multiple times enter the old age.
-
When the Young GC is used, the dynamic object age mechanism moves the object forward to the old age. Age is accumulated from small to large. When a certain age group is added, it is accumulated and exceeds survivor zone -xx :TargetSurvivorRatio, and the objects from this age group up enter the old age
-
In the Young GC, when Eden and From Space are copied To Space and the available memory of To Space is greater than the available memory of To Space, objects are directly migrated To the old age
4. The JVM’s space allocation guarantee mechanism may trigger the Full GC:
Space guaranteed allocation means that before Young GC occurs, the virtual machine checks whether the maximum contiguous space available in the old generation is greater than the total space of all objects in the new generation.
Understand JVM, GC algorithms, and performance tuning
If greater, the Young GC is safe.
If less, the virtual machine checks the HandlePromotionFailure setting to see if the guarantee failure is allowed.
If HandlePromotionFailure=true, then it continues to check whether the maximum available continuous space of the old age is greater than the average size of the objects that have been promoted to the old age. If so, a Young GC is attempted, but this Young GC is still risky. If it fails, the Full GC will be restarted. If less than or HandlePromotionFailure=false, do a Full GC directly instead.
“GC Easy Tools”
The gceasy(gceasy.io) tool is recommended to upload the GC file, and it will use a visual interface to show the GC situation
If you think it’s good, please like it and forward it. Thank you