[JVM advanced road] four: face memory overflow and memory leak

In Java, there are two main memory-related problems, memory overflow and memory leak .

  • Out of Memory ( Out Of Memory ) : When applying for memory, the JVM does not have enough memory space. The popular saying is to go to the pit and find that the pit is full.
  • Memory leak (Memory Leak) : It is to apply for the memory, but not release, resulting in a waste of memory space. Popular saying is that some people do not shit in the pit.

1. Memory overflow

In several memory areas of the JVM, in addition to the program counter, several other runtime areas have the possibility of out-of-memory (OOM) exceptions.

JDK 1.8 memory area

1.1, Java heap overflow

The Java heap is used to store object instances. We only need to continuously create objects and ensure that there is a reachable path between the GC Roots and the objects to avoid the garbage collection mechanism from clearing these objects. Then as the number of objects increases, the total capacity reaches the maximum heap. After the capacity is limited, a memory overflow exception will occur.

Let's look at an example of code:

/**
 * VM参数: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
    
    
    static class OOMObject {
    
    
    }

    public static void main(String[] args) {
    
    
        List<OOMObject> list = new ArrayList<OOMObject>();
        while (true) {
    
    
            list.add(new OOMObject());
        }
    }
}

Next, let's set the JVM parameters when the program starts. The memory size is limited to 20M, no expansion is allowed, and the virtual machine dumps the memory heap dump snapshot through the parameter -XX:+HeapDumpOnOutOf-MemoryError.

Set the JVM startup parameters in Idea as shown below:

Idea sets JVM parameters

Run it:

Heap memory overflow exception

The OutOfMemoryError exception of Java heap memory is the most common memory overflow exception in practical applications. When a Java heap memory overflow occurs, the exception stack information "java.lang.OutOfMemoryError" will be followed by a further prompt "Java heap space". The Java heap file snapshot file is dumped to the java_pid18728.hprof file.

To solve the abnormality of this memory area, the conventional method is to first analyze the heap dump snapshot from Dump through a memory image analysis tool (such as JProfiler, Eclipse Memory Analyzer, etc.).

See the memory usage information as follows:

Heap dump snapshot file opened by Jprofiler

Then you can view the code issues as follows:

Jprofiler view code issues

Common heap JVM related parameters:

-XX:PrintFlagsInitial: View the default initial value of all parameters -XX:PrintFlagsFinal: View the final value of all parameters (may be modified, no longer the initial value)
-Xms: Initial heap space memory (default is 1/64 of physical memory)
-Xmx: Maximum heap space memory (default 1/4 of the physical memory)
-Xmn: Set the size of the young generation (initial value and maximum value)
-XX:NewRatio: Configure the proportion of the young generation and the old generation in the heap structure
-XX:SurvivorRatio: set the ratio of Eden and S0/S1 space in the
-XX:MaxTenuringThresholdyoung generation: set the young generation Maximum age of garbage (default 15)
-XX:+PrintGCDetails: Output detailed GC processing log
Print GCbrief information: ① -XX:+PrintGC-verbose:gc
-XX:HandlePromotionFailure:Whether to set space allocation guarantee

1.2, virtual machine stack and local method stack overflow

The HotSpot virtual machine combines the virtual machine stack and the local method stack into one. Therefore, for HotSpot, although the -Xoss parameter (setting the local method stack size) exists, it actually has no effect. The stack capacity can only be determined by -Xss parameter to set. Regarding the virtual machine stack and the local method stack, there are two exceptions:

  • If the stack depth requested by the thread is greater than the maximum depth allowed by the virtual machine, StackOverflowErroran exception will be thrown .

  • If the virtual machine's memory stack allows for dynamic expansion, when the expansion of capacity does not apply to stack enough memory, it will throw OutOfMemoryErroran exception.

1.2.1、StackOverflowError

The HotSpot virtual machine does not support dynamic expansion of the stack. In the HotSpot virtual machine, the following two situations will cause a StackOverflowError.

  • Stack capacity is too small

    As follows, use the Xss parameter to reduce the stack memory capacity

/**
 * vm参数:-Xss128k
 */
public class JavaVMStackSOF {
    
    
    private int stackLength = 1;

    public void stackLeak() {
    
    
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) throws Throwable {
    
    
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
    
    
            oom.stackLeak();
        } catch (Throwable e) {
    
    
            System.out.println("stack length:" + oom.stackLength);
            throw e;
        }
    }

}

operation result:

Stack memory overflow

  • Stack frame too large

    As follows, through a long list of variables, to occupy the local variable table space.

    carbon

operation result:

image-20210324211958180

Whether it is because the stack frame is too large or the virtual machine stack capacity is too small, when the new stack frame memory cannot be allocated, the HotSpot virtual machine throws StackOverflowError exceptions.

1.2.2、OutOfMemoryError

Although it does not support dynamic expansion of the stack, by continuously creating threads, a memory overflow exception can also be generated on HotSpot.

It should be noted that there is no direct relationship between the memory overflow exception generated in this way and whether the stack space is sufficient, and it mainly depends on the memory usage status of the operating system itself. Because the operating system has limited memory for each process, the number of threads will naturally exceed the capacity of the process.

Creating a thread causes a memory overflow exception:

/**
 * vm参数:-Xss2M
 */
public class JavaVMStackOOM {
    
    
    private void dontStop() {
    
    
        while (true) {
    
    
        }
    }

    public void stackLeakByThread() {
    
    
        while (true) {
    
    
            Thread thread = new Thread(new Runnable() {
    
    
                public void run() {
    
    
                    dontStop();
                }
            });
            thread.start();
        }
    }

    public static void main(String[] args) throws Throwable {
    
    
        JavaVMStackOOM oom = new JavaVMStackOOM();
        oom.stackLeakByThread();
    }
}

The above is a relatively risky piece of code, which may cause the system to die. The results are as follows:

image-20210324213320530

1.3, method area and runtime constant pool overflow

Transition region mention about a method and a runtime constant pool where, after JDK1.7 string constant pool to the heap, JDK1.8 set aside a memory region in the direct -dimensional space to achieve side region.

String:intern() is a local method. If the string constant pool already contains a string equal to this String object, it returns a reference to the String object representing this string in the pool; otherwise, it will The string contained in the String object is added to the constant pool, and a reference to this String object is returned. In HotSpot virtual machines before JDK 6 or earlier, the constant pool is allocated in the permanent generation, and the permanent generation itself is not limited in memory, and errors may occur:

java.lang.OutOfMemoryError: PermGen space

1.4. Direct memory overflow of the machine

The size of the direct memory (Direct Memory) can be specified by the -XX: MaxDirectMemorySize parameter. If it is not specified, the default is the same as the maximum Java heap (specified by -Xmx).

Obtain the Unsafeinstance directly through reflection , and apply for memory allocation to the operating system through reflection:

/**
 * vm参数:-Xmx20M -XX:MaxDirectMemorySize=10M
 */
public class DirectMemoryOOM {
    
    
    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) throws Exception {
    
    
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
    
    
            unsafe.allocateMemory(_1MB);
        }
    }
}

operation result:

image-20210324215114989

An obvious feature of memory overflow caused by direct memory is that no obvious abnormalities will be seen in the Heap Dump file.

2. Memory leak

Memory collection, in short, means that objects that should be garbage collected are not garbage collected.

Memory leak

In the above figure: Object X refers to object Y. The life cycle of X is longer than the life cycle of Y. When the life cycle of Y ends, the garbage collector will not reclaim object Y.

Let's look at a few examples of memory leaks:

  • Static collection class causes memory leak

    The life cycle of the static collection is the same as that of the JVM, so the objects referenced by the static collection cannot be released.

public class OOM {
    
    
 static List list = new ArrayList();

 public void oomTests(){
    
    
   Object obj = new Object();

   list.add(obj);
  }
}
  • Singleton mode :

    Similar to the above example, the singleton object will exist in the entire life cycle of the JVM as a static variable after initialization. If the singleton object holds an external reference, then this external object will not be reclaimed by the GC, resulting in a memory leak.

  • Data connection, IO, Socket, etc. connections

    When the created connection is no longer in use, you need to call the close method to close the connection. Only after the connection is closed, the GC will reclaim the corresponding objects (Connection, Statement, ResultSet, Session). Forgetting to close these resources will result in continuous occupation of memory, which cannot be reclaimed by GC.

        try {
    
    
            Connection conn = null;
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("url", "", "");
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("....");
          } catch (Exception e) {
    
     
           
          }finally {
    
    
            //不关闭连接
          }
        }
  • Unreasonable scope of variables

    The definition scope of a variable is greater than the scope of its use, it is likely to have a memory leak; or the object is no longer used and the object is not set to null in time, which may cause a memory leak.

public class Simple {
    
    
    Object object;
    public void method1(){
    
    
        object = new Object();
        //...其他代码
        //由于作用域原因,method1执行完成之后,object 对象所分配的内存不会马上释放
        object = null;
    }
}
  • Non-static inner class that references an outer class

    The initialization of non-static inner classes (or anonymous classes) always depends on instances of outer classes. By default, each non-static inner class contains an implicit reference to its containing class . If this inner class object is used in the program, then even if the containing class object goes out of scope, it will not be recycled (inner class object Implicitly holds a reference to an external class object so that it cannot be recycled).

  • Hash value changes

    When the object Hash value changes, when using containers such as HashMap, HashSet, etc., the Hah value after the object is modified is different from the Hash value when stored in the container, and the current object cannot be deleted from the container alone , causing memory leaks.

  • Memory leak caused by ThreadLocal

    ThreadLocal can achieve thread isolation of variables, but if used improperly, memory leaks may be introduced.



reference:

[1]: "Deep Understanding of Java Virtual Machine: Advanced Features and Best Practices of JVM" by Zhou Zhipeng

[2]: "Java Virtual Machine Specification" translated by Zhou Zhipeng and others

[3]: "Secret Java Virtual Machine JVM Design Principle and Implementation" edited by Feng Yafei

[4]: What are memory leaks and memory leaks in Java? Let me give you a tasteful example

[5]: That Xiaobai hasn't understood the memory overflow yet, so I can only tell him with a case.

[6]: Intellij IDEA integrated JProfiler performance analysis artifact

[7]: JVM series (two)-JVM memory area in detail

[8] 1 article to figure out the reasons and solutions for 8 kinds of JVM out of memory (OOM)

[9]: In ten cases of JVM memory overflow, how many have you encountered?

[10]: JVM series (2): JVM memory leak and memory overflow and troubleshooting

Guess you like

Origin blog.csdn.net/sinat_40770656/article/details/115220345