When does an OutOfMemery exception happen? At first glance, it seems quite simple, but in fact, it is to investigate the understanding of the entire JVM, and this question can be turned over from the Internet to some messy answers, in fact, in the summary of basically four scenarios can be summarized.
Heap overflow
Heap memory is used to store object instances. As long as we keep creating objects and make sure there is a reachable path between the GC Roots and objects to avoid garbage collection, this exception will occur soon after the number of objects exceeds the maximum heap size limit.
Write a piece of code to test, set the heap memory size 2M.
public class HeapOOM {
public static void main(String[] args) {
List<HeapOOM> list = new ArrayList<>();
while (true) {
list.add(newHeapOOM()); }}}Copy the code
Run the code, and you will soon see an OOM exception.
General way of screen can be set by – XX: + HeapDumpOnOutOfMemoryError dump out when an exception occurs in the current Memory dump snapshot to analysis, analysis can be used the Eclipse Memory Analyzer (MAT) to analyze, individual files can be downloaded in the website.
If you are using IDEA, you can use the commercial version of JProfiler or the open source version of JVM-Profiler. In addition, IDEA2018 has built-in analysis tools, including Flame Graph and Call Tree capabilities.
Method area (run-time constant pool) and meta space overflow
Method area and heap, is a thread Shared areas, include the Class file information, runtime constant pool, the constant pool, pool runtime constants and constant pool is the main difference between dynamic, namely it doesn’t have to be in the Class file content in the constant pool can enter into the runtime constant pool, runtime can also can be new constants in the pool, Consider the String method intern().
-xx :MetaspaceSize=50 MB -xx :MaxMetaspaceSize=50 MB Since I am using the 1.8 version of the JDK, and before 1.8, the method area existed in PermGen (PermGen). After 1.8, the concept of PermGen was removed and turned into Metaspace (Metaspace). If it is the previous version, you can set PermSize MaxPermSize (PermGen).
private static String str = "test";
public static void main(String[] args) {
List<String> list = new ArrayList<>();
while (true){ String str2 = str + str; str = str2; list.add(str.intern()); }}Copy the code
When you run the code, you will find that the code reports an error.
Modify the configuration again, remove the meta space limit, change the heap memory size -Xms20m -Xmx20m, you can see the heap memory error.
Why is that? Intern () is itself a native method that returns a String representing the String in the pool of String constants if the pool already contains a String equal to the String. Otherwise, the String contained in this String is added to the constant pool, and a reference to the String object is mandatory.
After version 1.7, the string constant pool has been moved to the heap, so the heap is out of memory error will be reported. Before version 1.7, PermGen space error will be reported.
Direct memory overflow
Direct memory is not part of the data area when the virtual machine is running, and is not limited by the heap memory, but by the size of the machine’s memory. Common examples such as the ability to use native functions in NIO to allocate memory directly out of the heap can cause OOM problems.
The direct memory size can be specified by -xx :MaxDirectMemorySize. If not specified, it defaults to the same as the Java heap maximum value -xmx.
If the Dump file is small after OOM and NIO is used directly or indirectly, you may want to check if this is the cause.
Stack memory overflow
The stack is thread private and has the same lifetime as the thread. Each method creates a stack frame to store local variables, operand stack, dynamic link, method exit, and so on. The process of method invocation is the process of stack frame pushing and unloading.
In the Java Virtual Machine specification, two exceptions are defined for the virtual machine stack:
- If a thread requests a stack depth greater than the virtual machine allows, a StackOverflowError exception is thrown
- An OutOfMemoryError is thrown if the virtual machine stack can be dynamically expanded and enough memory cannot be obtained while expanding
Set -xSS160K. -xss represents the stack memory size per thread
public class StackOOM {
private int length = 1;
public void stackTest(a) {
System.out.println("stack lenght=" + length);
length++;
stackTest();
}
public static void main(String[] args) {
StackOOM test = newStackOOM(); test.stackTest(); }}Copy the code
The test found that no matter how the parameters are set under a single thread, it is a StackOverflow exception.
Try to make the code multithreaded and adjust -xss2m, because the larger the memory allocated for each thread, the fewer threads the stack can hold, and the more likely it is to overflow memory. On the other hand, if there is not enough memory, this parameter can be reduced to support more threads.
public class StackOOM {
private void dontStop(a) {
while (true) {}}public void stackLeakByThread(a) {
while (true) {
newThread(() -> dontStop()).start(); }}public static void main(String[] args) throws Throwable {
StackOOM stackOOM = newStackOOM(); stackOOM.stackLeakByThread(); }}Copy the code