preface

  • Be able to read the GC log to understand the various garbage collectors.
  • Understand the role of memory regions and resize JVM memory.
  • Know which region to use when creating objects.

Using VM parameters, read the GC log

Code and VM parameters, triggering the Minor GC

  • VM arguments
-Xms20M  // The maximum value of the heap
-Xmx20M  // The minimum of the heap
-Xmn10M  // The size of the young generation is the total size of Eden and the two Servivor, so 20-10=10M is the size of the old generation
-XX:+PrintGCDetails // Prints GC logs
-XX:SurvivorRatio=8  // Set the ratio of Eden to the younger generation
Copy the code

  • Review memory partitioning

  • code
public class GCLogTest {
    // Write nothing, the younger generation uses 2032K memory, should be different from machine to machine
    public static void main(String[] args) throws ClassNotFoundException {
        int size = 1024*1024;//M
        byte[] bytes = new byte[4*size];//4M
        byte[] bytes1 = new byte[3*size];//3M
        byte[] bytes2 = new byte[3*size];//3M
        System.out.println("GC log");
        // Memory contains not only created bytes [], but also objects that must be used to run Java programs.}}Copy the code

  • Description

Why is the log 9216K?

  • The young generation has one Eden region and two servivers, s0 and S1.
  • If the Eden area is set as 8, then s0 and S1 account for 1 respectively.
  • Only one of s0 and S1 will be used when used. The other one must not be used. So we’re going to lose 1,024K.
  • That is, 9216+1024 = 10240K = 10M, which means the difference between the set heap size and the actual heap size will be 1024K. Wasted by one of the Serviver sections.

It was observed that 4104K was used in the old age. How can we get it?

  • This can be calculated by memory changes before and after GC.
  • 5976-840 = 5136K, indicating that the young generation released 5136K capacity.
  • Content released by the younger generation may have gone back in time or been erased.
  • 5976-4944 = 1032K, indicating that the space released by the whole heap is 1032K.
  • 5136-1032 = 4104K, indicating that 1032K of the content released by the young generation was erased, and the remaining 4104K was removed from the old era.

Code to trigger the Full GC

  • code
public class GCLogTest {
    // Write nothing to the young generation, use 2032K memory, different machines should be different
    public static void main(String[] args) throws ClassNotFoundException {
        int size = 1024*1024;//M
        byte[] bytes = new byte[4*size];//4M
        byte[] bytes1 = new byte[4*size];//4M
        byte[] bytes2 = new byte[3*size];//3M
        System.out.println("GC log"); }}Copy the code

  • Explain Full GC

The object was created with a larger capacity than the Full GC triggered above, but the Full GC was not triggered

The code above is 11M byte[], which triggers the Full GC

  • Create a 13 m byte []
public class GCLogTest {
    // Write nothing to the young generation, use 2032K memory, different machines should be different
    public static void main(String[] args) throws ClassNotFoundException {
        int size = 1024*1024;//M
        byte[] bytes = new byte[4*size];//4M
        byte[] bytes1 = new byte[3*size];//3M
        byte[] bytes2 = new byte[size];//1M
        byte[] bytes3 = new byte[5*size];//5M
        System.out.println("GC log"); }}Copy the code

  • Why didn’t the Full GC trigger when you created something that was quite large
    • Objects are created in the old age when they cannot be created in the new generation.
      • Don’t try to split the object, one part in the new generation, the other part in the old age, it is impossible.
  • The following situations are also created directly in the old era
public class GCLogTest {
    // Write nothing to the young generation, use 2032K memory, different machines should be different
    public static void main(String[] args) throws ClassNotFoundException {
        int size = 1024*1024;//M
        byte[] bytes = new byte[8*size];//8M, plus others, will exceed the Cenozoic size
        System.out.println("GC log"); }}Copy the code

public class GCLogTest {
    // Write nothing to the young generation, use 2032K memory, different machines should be different
    public static void main(String[] args) throws ClassNotFoundException {
        int size = 1024*1024;//M
        byte[] bytes = new byte[11*size];//11M, the object exceeds the size of Cenozoic and old age
        System.out.println("GC log"); }}Copy the code

The threshold value

Use Java -xx :+PrintCommandLineFlags on the terminal to check the JVM startup parameters. Simple chat UseCompressedOops and UseCompressedClassPointers JVM parameters between the two.

A VM parameter sets the threshold for objects created in the old age

  • Set a threshold for creating objects larger than this threshold, regardless of whether there is enough space for the new generation to create objects in the old generation.
  • The following are VM parameters
-Xms20M
-Xmx20M
-Xmn10M
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:PretenureSizeThreshold=4194304  // The threshold is 4M
Copy the code
  • Code to create a byte array of 5M
public class ThresholdTest {
    public static void main(String[] args) {
         int size = 1024*1024;
         byte[] bytes = new byte[5*size]; }}Copy the code

For the threshold to work, the garbage collector needs to be single-threaded

  • Start the single-threaded garbage collector based on the original VM parameter
-XX:+UseSerialGC  
Copy the code

Set the age threshold of an object in the Servivor area

  • Minor GC is a garbage collection action that occurs in the new generation using a copy algorithm.
  • The New generation is where almost all Java objects are born, and the new generation is a frequent area for GC garbage collection.
  • After an object is born in Eden (including a Survivor region, assumed to be from) and after a Minor GC, if the object is still alive and can be accommodated by another Survivor region (already assumed to be from region), The to region has enough memory space to store Eden and surviving objects in the FROM region. The replication algorithm is used to copy the surviving objects to another Survivor region (the TO region). Then clean up the Eden and Survivor regions (i.e. from regions) used, and set the age of these objects to 1. After that, each time the object survives a Minor GC in Survivor region, the age of the object will be + 1.
  • When the age reaches a certain value, if the object is still being replicated in the Servivor area, it will be moved to the old age.
  • -XX:MaxTenuringThreshold: indicates that the age will be moved to the old age when it reaches the maximum value.
    • The default value of this parameter is 15, 6 in CMS, and 15 in G1 (in Jvw, this value is represented by four bits, so the maximum value is 1111, or 15).
    • Is the maximum value set. The object may be moved to the old age when the age reaches the maximum value, but it will definitely be moved to the old age when the age reaches the maximum threshold set.
    • Using -xx :TargetSurvivorRatio=value The JVM dynamically sets its size as the case may be, but does not exceed the value it was manually set to.
  • After multiple GCS, surviving objects are stored back and forth between From and To Survivor, assuming that the two Spaces are large enough To hold the data.
  • In the GC algorithm, the age of each object is calculated, and if you reach a certain age and find that the total size is more than 50% of the Survivor space, then you need to adjust the width value instead of waiting for the default 15 GCS to complete the pull-up (moving to the old age). Because this results in insufficient Survivor space, the threshold needs to be adjusted to allow these surviving objects to be promoted as quickly as possible.

To demonstrate the progression of an object from a young generation to an old generation

  • The following are the code VM parameters
-Xmx200M // The heap size is 200M
-Xmn50M  // Cenozoic size
-XX:TargetSurvivorRatio=60 // If an object in a Servivor is greater than 60% of the total size of a Servivor,
                            // Re-estimate the TenuringThreshold, i.e., how much the updated age will be to enter the old age
-XX:+PrintTenuringDistribution  // Prints the age of the object
-XX:+PrintGCDetails  // Prints GC logs
-XX:+PrintGCDateStamps  // Print the time of GC
-XX:+UseConcMarkSweepGC  // The CMS garbage collector is used in the old days
-XX:+UseParNewGC   // The new generation uses the ParNew collector
-XX:MaxTenuringThreshold=3 // Age threshold, maximum
Copy the code

Serivivor is not specified

  • code
public class TenuringTest {
    public static void main(String[] args) throws InterruptedException {
        byte[] bytes = new byte[512 * 1024];
        byte[] bytes1 = new byte[512 * 1024];// If the main method is not finished, it will not be erased
        for (int i = 1; i < 7; i++) {
            willGC();
            Thread.sleep(1000);
            System.out.println("loop: 00" + i);
        }
        byte[] bytes2 = new byte[1024 * 1024];
        byte[] bytes3 = new byte[1024 * 1024];
        byte[] bytes4 = new byte[1024 * 1024];
        byte[] bytes5 = new byte[1024 * 1024];
        willGC();
        System.out.println("loop: 007");
        Thread.sleep(1000);
        willGC();
        System.out.println("loop: 008");
        Thread.sleep(1000);
        System.out.println("end...");
    }

    private static void willGC(a) {// After the call, the created object can be eliminated
        for (int i = 0; i < 40; i++) {
            byte[] bytes = new byte[1024 * 1024];// 1 M}}}Copy the code

(Max 3) Indicates that the maximum threshold determined by dynamic judgment is 3, which is determined by -xx :MaxTenuringThreshold=3. Desired survivor size 3145728 bytes

  • Because the ratio of Servivor is not specified, the default is 8:1:1. -xmn50m specifies the size of the new generation to be 50M, so 40:5:5.
  • -xx :TargetSurvivorRatio=60, indicating the rejudgment threshold (5 * 60% = 3M = 3145728 bytes) of a Serivior zone that exceeds 60%.
  • Rejudge the threshold when one of the Serivior objects reaches 3145728 bytes.

summary

-Xms20M  // The maximum value of the heap
-Xmx20M  // The minimum of the heap
-Xmn10M  // The size of the young generation is the total size of Eden and the two Servivor, so 20-10=10M is the size of the old generation
-XX:+PrintGCDetails // Prints GC logs
-XX:SurvivorRatio=8  // Set the ratio of Eden to the younger generation
-XX:+UseSerialGC  // Use single-threaded garbage collector, both new generation and old generation
-XX:PretenureSizeThreshold=4194304  // The size threshold for creating objects is 4M. If the threshold exceeds 4M, create objects in the old age directly
-XX:TargetSurvivorRatio=60 // If an object in a Servivor is greater than 60% of the total size of a Servivor,
                            // Re-estimate the TenuringThreshold, i.e., how much the updated age will be to enter the old age,
-XX:+PrintTenuringDistribution  // Prints the size of each age object
-XX:+PrintGCDetails  // Prints GC logs
-XX:+PrintGCDateStamps  // Print the time of GC
-XX:+UseConcMarkSweepGC  // The CMS garbage collector is used in the old days
-XX:+UseParNewGC   // The new generation uses the ParNew collector
-XX:MaxTenuringThreshold=3 // Age threshold, maximum
Copy the code