[In-depth understanding of JVM-OutOfMemoryError combat]

In addition to the program counter, other runtime data areas of jvm may appear OOM. This section is a simple actual combat, and summarizes the pits under the idea.

I. Introduction

1. The show
  • Verify the content stored in each runtime data area of ​​the jvm through code
  • When you encounter OOM in actual work, you can quickly determine which area is OOM based on the exception information, know what kind of code may cause OOM in these areas, and how to deal with it after OOM occurs.
2. Set the jvm parameter mining pit on the idea

Don't use idea's jvm startup parameters as setting jvm parameters

(1) Wrong setting method 1

1. Open the bin directory of the idea installation directory
2. Open the idea64.exe.vmoptions file in Notepad
3. -Xms20m-Xmx20m
4. Save and restart the idea
5. The idea is exploded and cannot be opened. (Internal error. Please report to http://jb.gg/ide/critical-startup-errors)

(2) Wrong setting method 2

1. Idea-help -Edit custom Optionms-pop-up window (see below)-create
2. File created
3. Modify parameters-Xms20m-Xmx20m
4. Save and restart again

Insert picture description here

(3) The above bug was reported when the idea was launched.

1. Delete the file:
C drive-user-Administrator-.IntelliJIdea20xx.x folder
2. Restart the idea installation.

3. Set JVM parameters correctly

(1) Click Edit Config...
Insert picture description here
(2) Find the edit window and click to open
Insert picture description here
(3) Parameter configuration (mine is as follows)
Insert picture description here

(4) Return to this window and find the Save XXX (mine is Save OOMHeap) class and save it

Insert picture description here

(5) Common parameters

------------------------------------------------------------------------
1、堆:
-Xms:JVM初始分配的堆内存
-Xmx:JVM最大允许分配的堆内存,按需分配
------------------------------------------------------------------------
2、栈:
-Xss 为jvm启动的每个线程分配的栈内存大小,默认JDK1.4中是256K,JDK1.5+中是1M 
------------------------------------------------------------------------
3、方法区:
-XX:PermSize   初始内存
-XX:MaxPermSize 最大内存
------------------------------------------------------------------------
4、本机直接内存
-XX:MaxDirectByteBuffer
------------------------------------------------------------------------
5、生成堆的log文件:
-XX:+HeapDumpOnOutOfMemoryError:让虚拟机在堆内存溢出时生成快照日志
-XX:HeapDumpPath=C:\Users\Administrator\Desktop\error_logs:生成快照日志的路径(这里为桌面)
------------------------------------------------------------------------

Two, OOM actual combat

1. Java heap overflow (heap oom)

(1) First set the parameters

-Xms60m 
-Xmx60m 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=C:\Users\Administrator\Desktop\error_logs

(2) Code simulation and its results

/**
 * Create by SunnyDay on 2019/10/05
 */
public class OOMHeap {
    
    
    static class OOMObject{
    
    }
    
    public static void main(String[] args){
    
    
        List<OOMObject> list = new ArrayList<>();
        while (true){
    
    
            list.add(new OOMObject());
        }
    }
}
// log:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:261)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
	at java.util.ArrayList.add(ArrayList.java:458)
	at test.OOMHeap.main(OOMHeap.java:15)

It will prompt when the heap memory overflows as abovejava.lang.OutOfMemoryError: Java heap space

(3) Tool analysis
Insert picture description here
Insert picture description here

Use this tool to analyze the generated error_log file and
analyze whether it is a memory leak or an oom
1. Memory leak: By viewing the GC root reference chain through the tool, you can find out how the leaked object is related to the GC root through the path, causing the garbage collector to fail to recycle . ( That is, large objects have been referenced and cannot be recycled. This is a memory leak, and more leaks will lead to oom)
2. Not a memory leak: This means that the objects in memory need to survive.

  • At this time, check the virtual machine's heap parameters (-Xms and, -Xmx) to compare with the physical memory to see if it can be increased
  • The code detects whether some objects have a long life cycle and a long time holding state to try to reduce the memory consumption during the code runtime.

ps: The above is just a simple idea to solve, the use and verification of tools refer to the notes in Chapter 3 later.

2. Virtual machine stack and local method stack overflow

Because HotSpot virtual machine does not distinguish between virtual machine stack and local method stack. Therefore, the -Xoss parameter (setting the size of the local method stack) is invalid for the HotSpot virtual machine. The stack capacity is set by -Xss.

(1) Review of abnormalities in these two areas

1. If the depth of the thread request is greater than the maximum depth allowed by the jvm, Stack Overflow will be thrown.
2. If the virtual machine cannot apply for enough memory space when the virtual machine expands the stack, it will throw OOM.
Question:
When the stack space cannot be allocated, is the memory too small or the stack space already used is too large.
Explanation: The above situation is essentially just a different description of the same thing.

(2) Experimental test: set the memory to 128K under single thread


package test;
/**
 * Create by SunnyDay on 2019/10/05
 * -Xss128k
 */
public class StackSOF {
    
    

    private int stackLength = 1;

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

    public static void main(String[] args) {
    
    
        StackSOF stackSOF = new StackSOF();
        try {
    
    
            stackSOF.stackLeak();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

// log:
Exception in thread "main" java.lang.StackOverflowError
	at test.StackSOF.stackLeak(StackSOF.java:8)
	at test.StackSOF.stackLeak(StackSOF.java:9)
	at test.StackSOF.stackLeak(StackSOF.java:9)
	...
	...
	at test.StackSOF.stackLeak(StackSOF.java:9)
	at test.StackSOF.main(StackSOF.java:15)

The above restrictions:
1. Use -Xss to reduce the stack capacity. As a result, Stack Overflow will be thrown, and the output stack depth will be reduced accordingly when the exception occurs.
2. Define a large number of local variables and increase the length of the local variable table in this method. As a result, Stack Overflow is thrown, and the output stack depth is reduced accordingly when the exception occurs.

(3) Single-threaded conclusion

Under single thread,Whether it isStack frame too largestill isVirtual machine stack capacity is too small, When the memory cannot be allocated jvmThrowAll areStack Overflow exception

(4) Multi-threaded conclusion

It is possible to generate oom by continuously creating threads, but the memory overflow caused by this has nothing to do with whether the stack space is large enough. , In this casePer threadofThe larger the memory allocated by the stack,insteadThe easier it is to produce oom.

the reason:

1. The memory allocated by the operating system to each process is limited first. For example, 32-bit windows limits the memory usage of a single process to 2GB.
2. Local method stack memory + java stack memory = 2GB- maximum heap size-MaxPermSize (maximum method area capacity)
ps: The memory of the program counter is very small. Ignore, jvm virtual machine When the memory consumed by the process itself is not counted. The larger the stack capacity allocated by each thread, the smaller the number of threads that can be created, and the easier it is to run out of remaining memory when creating threads.

(5) Solution

Single-threaded memory overflow:
1. The stack with errors can be read when a Stack Overflow exception occurs. It is convenient to find out the problem.
2. If the default parameters of the virtual machine are used, the stack depth can reach 1000-2000 in most cases. It is completely sufficient for normal method calls including recursion.
Memory overflow caused by multithreading:
1. InCannot reduce the number of threadsorWithout replacing the 64-bit virtual machine, Only throughReduce max heapwithReduce stack capacityComeIn exchange for more threads.

(6) Code

package test;
/**
 * Create by SunnyDay on 2019/10/06
 */
public class StackOOM {
    
    
    
    private void  dontStop(){
    
    
        while(true){
    
    
            
        }
    }
    
    public void moreThread(){
    
    
        while(true){
    
    
            new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                   dontStop(); 
                }
            }).start();
        }
    }
    public static void main(String[] args) {
    
    
        new StackOOM().moreThread();
    }
}

Note: The execution of the above code needs to save the current work.
In the windows platform, the thread of java is mapped to the kernel thread of the operating system. The above may cause the operating system to die.

3. Method area and runtime constant pool overflow

(1) Adjust the space size of the method area

-XX:PermSize=500k
-XX:MaxPermSize=500k

(2)code1

/**
 * Create by SunnyDay on 2019/10/06
 */
public class ConstantPoolOOM {
    
    
    public static void main(String[] args) {
    
    
      
        List<String> list = new ArrayList<>();
        int i = 0;
        while(true){
    
    
            // 一直往常量池放不同对象
            list.add(String.valueOf(i++).intern());
            System.out.println();
        }
    }
}

1. The above code appears OOM in jdk1.6 or version less than 1.6.
2. The program of jdk1.7 or later version has been running (the constant pool is moved out of the method area (permanent generation) since 1.7)

(2) Review the intern method of String again

1. It is a native method.
2. If there is already a string equal to this String object in the string constant pool, return the object of this string in the constant pool. Otherwise, the string contained in the String objectAdd to constant pool, And return a reference to the string object.

       String string1 = new StringBuilder("计算机").append("软件").toString();
        System.out.println(string1.intern() == string1);
    

1. False in jdk1.6 (the two object references are different, one is the address on the heap, the other is added to the constant pool, and an address is created for it). True in jdk1.8 (new is to create a memory address on the heap, intern is to record this address in the constant pool as the same object address)
2. After jdk1.7, the intern method will no longer copy instances, butConstant poolinRecord the first instance reference
3. Extension In fact, the default string of java has appeared in the constant pool such as DEFAULT_NAME in the Application class (com.sun.glass.ui.Application).

(3) Experiment

The method area stores class information at runtime. When the basic idea runs, a large number of classes fill up the method area.

Method area overflow is also a common OOM, and special attention should be paid to the garbage collection status of the class in applications that often dynamically generate a large number of classes.
Common scenarios that can cause the method area to overflow:
1. Use of CGLib technology
2. A large number of JSP dynamically generated jsp files (jsp is compiled into clss files when it is first run)
3. OSGi-based applications (the same class is used by different class loader Treated as a different class when loaded)

4. Direct memory overflow of the machine

When not manually specified, the default is the same as the default value of the maximum heap.

(1) Chestnuts

//-XX:MaxDirectByteBuffer10M     限制为10M

 Field  field = Unsafe.class.getDeclaredFields()[0] ;
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);
        while (true){
    
    
            unsafe.allocateMemory(1024*1024);
        }
// logs:
Exception in thread "main" java.lang.OutOfMemoryError
	at sun.misc.Unsafe.allocateMemory(Native Method)
	at methodarea.MethodAreaOOM.main(MethodAreaOOM.java:22)

OOM caused by direct memory has obvious characteristics:
1. No obvious abnormalities can be seen in the log file exported by Heap Dump.
2. The error log file is small. You can consider whether this is the reason for program introduction or directly using NIO.

Guess you like

Origin blog.csdn.net/qq_38350635/article/details/102164205