JVM Series: In-depth explanation of JVM memory overflow analysis!

Keywords: Java jvm Database network

JVM memory overflow

1. heap memory overflow

The main storage objects and arrays are in heap memory. As long as these objects are created continuously and there is a reachable path between GC Roots and objects to avoid garbage collection and collection mechanism clearing these objects, when the space occupied by these objects exceeds the maximum heap capacity, an exception of OutOfMemoryError will occur. An example of heap memory exceptions is as follows:

/**

Set the maximum heap and minimum heap: - Xms20m -Xmx20m

At runtime, instance objects of OOMObject classes are constantly created in the heap, and before the end of while execution, there is an accessible path between GC Roots (oomObjectList in code) and objects (each OOMObject object), so the garbage collector can't recycle them, resulting in memory overflow.

*/

public class HeapOOM {

static class OOMObject {

}

public static void main(String[] args) {

    List<OOMObject> oomObjectList = new ArrayList<>();

    while (true) {

        oomObjectList.add(new OOMObject());

    }

}
}

Exceptions will be reported after running, as you can see in the stack information:

Java.lang.OutOfMemoryError: Information from Java heap space that indicates an exception to memory overflow in heap memory space.

The newly generated objects are initially assigned to the Cenozoic, and Minor GC will be carried out once the Cenozoic expires. If the space of Minor GC is insufficient, the objects satisfying the conditions of the Cenozoic and the Minor GC will be put into the old generation. Full GC will be carried out when the space of the old generation is insufficient, and then an OutOfMemoryError exception will be thrown if the space is insufficient to store the new objects.

Common reasons: too much data loaded in memory, such as too much data extracted from the database at one time; too many references to objects in the collection and not empty after use; too many duplicate objects generated by dead loops or loops in the code; unreasonable allocation of heap memory; network connection problems, database problems, etc.

2. Virtual Machine Stack/Local Method Stack Overflow

(1) StackOverflow Error: When the depth of the stack requested by a thread is greater than the maximum depth allowed by the virtual machine, a StackOverflow Error is thrown. Simply understood is that when the number of stack frames in the virtual machine stack is too large (the number of methods invoked by a thread is too large), a StackOverflow Error exception is thrown.

The most common scenario is infinite recursive method calls, as follows:

/**

Set the stack size for each thread: - Xss256k

At runtime, the doSomething() method is constantly invoked, and the main thread creates stack frames and merges them into the stack, which results in the stack becoming deeper and deeper, and eventually leads to stack overflow.

*/

public class StackSOF {

private int stackLength=1;

public void doSomething(){

        stackLength++;

        doSomething();

}

public static void main(String[] args) {

    StackSOF stackSOF=new StackSOF();

    try {

        stackSOF.doSomething();

    }catch (Throwable e){//Notice that Throwable is captured

        System.out.println("Depth of stack:"+stackSOF.stackLength);

        throw e;

    }

}
}

After the above code is executed, it throws:

Exception in thread "Thread-0" java.lang.StackOverflowError Exception.

(2) OutOfMemoryError: If the virtual machine cannot request enough memory space when extending the stack, it throws OutOfMemoryError.

We can understand that the space available for stacks in virtual machines is available physical memory - maximum heap memory - maximum method area memory, such as 4G memory for a machine, 2G memory for systems and other applications, 2G physical memory available for virtual machines, 1G maximum heap memory and 512M maximum method area memory, which is about 512M for stacks, if I were They set the size of each thread stack to 1M, and the virtual machine can create 512 threads at most. If more than 512 threads are created, there will be no room for the stack, and the OutOfMemoryError exception will be reported.

image

An example of an OutOfMemoryError that can be generated on the stack is as follows:

/**

Set the stack size for each thread: - Xss2m

At runtime, new threads are continuously created (and each thread is continuously executed), each thread on a stack, and ultimately there is no extra space to allocate to the new thread, resulting in OutOfMemoryError

*/

public class StackOOM {

private static int threadNum = 0;

public void doSomething() {

    try {

        Thread.sleep(100000000);

    } catch (InterruptedException e) {

        e.printStackTrace();

    }

}

public static void main(String[] args) {

    final StackOOM stackOOM = new StackOOM();

    try {

        while (true) {

            threadNum++;

            Thread thread = new Thread(new Runnable() {

                @Override

                public void run() {

                    stackOOM.doSomething();

                }

            });

            thread.start();

        }

    } catch (Throwable e) {

        System.out.println("Current number of active threads:" + threadNum);

        throw e;

    }

}
}

Exceptions are reported when the above code runs

In the stack information, you can see the information of java.lang.OutOfMemoryError: unable to create new native thread s, unable to create new threads, indicating that the memory overflow exception was generated when the stack was extended.

Summary: When there are fewer threads, a thread requesting too much depth will report StackOverflow exception. To solve this problem, we can increase the depth of the stack (increase the size of the stack space), that is to say, set the value of - Xss larger, but in general it is more likely to be a code problem; when the virtual machine generates threads, it is impossible to apply for the stack space for the thread.

OutOfMemoryError exception will be reported. To solve this problem, the stack depth can be reduced appropriately. That is to say, the value of - Xss is set smaller. Each thread occupies less space, and the total space can accommodate more threads. However, the operating system has a limited number of threads for a process, with an empirical value of about 3000-5000.

Before jdk1.5 - Xss defaults to 256k, after jdk1.5 defaults to 1M. This option is still very hard for the system, and should be set carefully according to the actual situation.

3. Method Area Overflow

As mentioned earlier, method zones are mainly used to store class information, constants, static variables loaded by virtual machines, and compiled code by compilers, so the reason for overflow of method zones is that there is not enough memory to store these data.

Because the string constant pool existed in the method area before jdk1.6, the virtual machine based on JDK1.6 can simulate the OutOfMemoryError exception of the method area by continuously generating inconsistent strings (guaranteeing reachable paths between GC Roots and GC Roots); but the method area also stores loaded class information, so the virtual machine based on jdk1.7 can A large number of classes are created dynamically to simulate method area overflow.

/**

Set the maximum and minimum space of the method area: - XX:PermSize=10m -XX:MaxPermSize=10m

At runtime, subclasses of JavaMethodAreaOOM are created continuously through cglib, and more and more information about classes in the method area is generated, and no memory allocated for new classes eventually leads to memory overflow.

*/

public class JavaMethodAreaOOM {

public static void main(final String[] args){

   try {

       while (true){

           Enhancer enhancer=new Enhancer();

           enhancer.setSuperclass(JavaMethodAreaOOM.class);

           enhancer.setUseCache(false);

           enhancer.setCallback(new MethodInterceptor() {

               @Override

               public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

                   return methodProxy.invokeSuper(o,objects);

               }

           });

           enhancer.create();

       }

   }catch (Throwable t){

       t.printStackTrace();

   }

}
}

The above code will be reported after running:

Java.lang.OutOfMemoryError: An exception to PermGen space indicates a memory overflow error in the method area.

4. Local Direct Memory Overflow

Local direct memory is not part of the data area of the virtual machine runtime, nor is it defined in the Java Virtual Machine Specification. However, when NIO-related operations are used in Java (such as ByteBuffer's allocteDirect method, which requests local direct memory), there may also be memory overflow anomalies.

summary

JVM memory area partition is convenient for it to manage its own memory more efficiently. When the memory overflow caused by JVM occurs in the program, different analysis and processing should be done according to different situations.

Last

Follow-up will continue to update JVM thematic knowledge and more architecture topics, write the bad place also hope Daniel can point out, you feel good can point a praise under the attention of me, just stationed, and will share more articles in the future!

Posted by slobodnium on Thu, 02 May 2019 20:50:38 -0700