The Java virtual machine specification stipulates that the JVM memory is divided into several blocks, such as heap, stack, program counter, method area, etc. In the implementation of Hotspot jvm, the heap memory is divided into three parts, the new generation, the old age, and the persistent band. The persistent band implements the method area specified in the specification, and different parts of the memory model will have corresponding OutOfMemoryError errors. Next, let's discuss it separately. I believe most developers have encountered this error, and the reasons for this error are mostly caused by the following reasons:
The JVM memory is too small and the program is not tight, resulting in too much garbage.
There are several common causes of OutOfMemoryError exceptions:
Common error prompts for this error:
StackOverflowError
Stack Overflow throws a java.lang.StackOverflowError error. This occurs because the depth of the stack exceeds the maximum depth allowed by the virtual machine when the method is running. This situation usually occurs because of program errors. For example, writing a dead recursion may cause this situation. Let’s simulate the memory overflow in this situation through a piece of code.
import java.util.*; import java.lang.*; public class OOMTest{ public void stackOverFlowMethod(){ stackOverFlowMethod(); } public static void main(String... args){ OOMTest oom = new OOMTest(); oom.stackOverFlowMethod(); } } Running the above code will throw the following exception:
Exception in thread "main" java.lang.StackOverflowError at OOMTest.stackOverFlowMethod(OOMTest.java:6)
Heap overflow (OutOfMemoryError:java heap space)
When the heap memory overflows, the virtual machine throws java.lang.OutOfMemoryError:Java heap space. When this happens, we need to analyze it specifically based on the dump file generated when the memory overflows (-XX: +HeapDumpOnOutOfMemoryErrorjvm startup parameter needs to be added). When such a problem occurs, it may be a memory leak or a memory overflow.
If memory leaks, we need to find out how the leaked object is referenced by GC ROOT, and then analyze the cause of the leak through the reference chain.
If there is a memory overflow problem, it is often because the program needs more memory than the memory we configure for the virtual machine. In this case, we can use the -Xmx to solve this problem.
Below we demonstrate the overflow of this situation through the following code:
import java.util.*; import java.lang.*; public class OOMTest{ public static void main(String... args){ List<byte[]> buffer = new ArrayList<byte[]>(); buffer.add(new byte[10*1024*1024]); } } We run the above code through the following command:
java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest
The program enters the following information:
[GC 1180K->366K(19456K), 0.0037311 secs] [Full GC 366K->330K(19456K), 0.0098740 secs] [Full GC 330K->292K(19456K), 0.0090244 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at OOMTest.main(OOMTest.java:7)
From the running results, we can see that the JVM performed Minor gc once and twice Major gc. From the output of Major gc, it can be seen that the usage rate of the old area after gc is 134K, and the byte array is 10M, which adds up to be greater than the space of old generation, so an exception is thrown. If -Xms21M and -Xmx21M are adjusted, then the gc operation will not be triggered and there will be no exception.
Through the above experiment, a conclusion has been verified from the side: when the object is larger than the remaining memory of the new generation, it will be placed directly into the old age. When the remaining memory of the old age is still unable to be put down, garbage collection will be triggered. If it still cannot be put down after collection, a memory overflow exception will be thrown.
PermGen space
We know that Hotspot jvm implements the method area in the Java virtual machine specification through persistent bands, and the runtime constant pool is stored in the method area. Therefore, the persistent band overflow may be the runtime constant pool overflow, or the class objects saved in the method area are not recycled in time or the memory occupied by class information exceeds our configuration. When the persistence band overflows, java.lang.OutOfMemoryError: PermGen space is thrown.
I may experience this problem in the following scenarios when working.
When using hot deployment of some application servers, we will encounter hot deployment several times and find that memory overflows. This is because after each hot deployment, the original class has not been uninstalled.
If the application itself is larger and involves more class libraries, this problem may also occur when the memory we allocate to the persistent band (set by -XX:PermSize and -XX:MaxPermSize) is relatively small.
Some third-party frameworks, such as spring and hibernate, all implement some enhanced functions through bytecode generation technology (such as CGLib), which may require a larger method area to store dynamically generated Class files.
We know that string constants in Java are placed in a constant pool. When the String.intern() method is run, it will check whether objects equal to this string are stored in the constant pool. If there exists, directly return a reference to the object in the constant pool. If it does not exist, add this string to the constant pool first, and then return the reference to the string. Then we can simulate the overflow of the constant area during runtime through the String.intern method. Let’s simulate this situation through the following code:
import java.util.*; import java.lang.*; public class OOMTest{ public static void main(String... args){ List<String> list = new ArrayList<String>(); while(true){ list.add(UUID.randomUUID().toString().intern()); } } }We run the above code through the following command:
java -verbose:gc -Xmn5M -Xms10M -Xmx10M -XX:MaxPermSize=1M -XX:+PrintGC OOMTest
The input after running is shown in the figure below:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.String.intern(Native Method) at OOMTest.main(OOMTest.java:8)
Through the above code, we successfully simulated the constant pool overflow during runtime. From the PermGen space in the output, we can see that the persistent band is indeed overflowing, which also verifies the statement that the Hotspot jvm implements the method area through persistent band as mentioned earlier.
OutOfMemoryError:unable to create native thread
Finally, let's take a look at the error java.lang.OutOfMemoryError:unable to create natvie thread. When this happens, it is usually caused by the following two situations:
The number of threads created by the program exceeds the operating system limit. For Linux systems, we can view this limitation through ulimit -u.
The memory allocated to the virtual machine is too large, resulting in too little native memory required when creating threads. We all know that the operating system has a limit on the memory of each process. When starting Jvm, it is equivalent to starting a process. If one of our processes occupies 4G of memory, then the remaining memory calculated through the following formula is the memory that can be used when building a thread stack. Total available memory for thread stack = 4G-(value of -Xmx)-(-XX:value of MaxPermSize)- The memory occupied by the program counter is shown by the above formula that the larger the values of -Xmx and MaxPermSize, the smaller the available space for the thread stack. When the stack capacity configured by the -Xss parameter remains unchanged, the smaller the number of threads that can be created. Therefore, if it is impossible to create native thread due to this situation, then we either increase the total memory occupied by the process, or reduce -Xmx or -Xss to achieve the purpose of creating more threads.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.