Common MEMORY overflow exceptions and code examples in Java programming

  • 2020-11-30 08:22:39
  • OfStack

The Java heap is used to store object instances, so if we keep creating objects and ensure that there is an accessible path between GC Root and the object being created so that the object is not garbage collected, then when too many objects are created, heap will run out of memory and throw an OutOfMemoryError exception.


/**
 * @author xiongyongshun
 * VM Args: java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
 */
public class OutOfMemoryErrorTest {
  public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    int i = 0;
    while (true) {
      list.add(i++);
    }
  }
}

Above is a code that throws an OutOfMemoryError exception. As you can see, it prevents garbage collection by constantly creating objects and storing them in list, so that when there are too many objects, the heap will overflow.

With ES13en-ES14en10ES15en-ES16en10ES17en-ES18en :+HeapDumpOnOutOfMemoryError we set the heap memory to 10 megabytes and use the parameter -XX :+HeapDumpOnOutOfMemoryError to let JVM print out the current memory snapshot for subsequent analysis when an OutOfMemoryError exception occurs.

After compiling and running the above code, the output is as follows:


>>> java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError com.test.OutOfMemoryErrorTest                                              16-10-02 23:35
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid1810.hprof ...
Heap dump file created [14212861 bytes in 0.125 secs]
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 com.test.OutOfMemoryErrorTest.main(OutOfMemoryErrorTest.java:15)

Java stack StackOverflowError

As we know, JVM's runtime data area has a memory area called the virtual machine stack. The purpose of this area is to create a stack frame when each method executes, which is used to store information such as local variable scale, operand stack, method exit, etc.

So we can create a recursive call of infinite recursion, and when the recursion gets too deep, it will run out of stack space, causing the StackOverflowError exception.

Here's the code:


/**
 * @author xiongyongshun
 * VM Args: java -Xss64k
 */
public class OutOfMemoryErrorTest {
  public static void main(String[] args) {
    stackOutOfMemoryError(1);
  }

  public static void stackOutOfMemoryError(int depth) {
    depth++;
    stackOutOfMemoryError(depth);
  }
}

When the above code is compiled and run, the following exception information is output:


Exception in thread "main" java.lang.StackOverflowError
  at com.test.OutOfMemoryErrorTest.stackOutOfMemoryError(OutOfMemoryErrorTest.java:27)

The method area is out of memory


 Pay attention to ,  because  JDK8  The permanent generation has been removed ,  In its place  metaspace,  So in  JDK8  In the ,  Neither of the following examples will lead to  java.lang.OutOfMemoryError: PermGen space  abnormal .

Run-time constant pool overflow

At the time of Java 1.6 and earlier versions of HotSpot JVM, there was the concept of permanent generations, that is, GC's generational collection mechanism was extended to method areas. In the method area, one part of the memory is used to store the constant pool, so if you have too many constants in your code, you run out of constant pool memory, which can lead to memory leaks. So how do you add a lot of constants to a constant pool? The String.intern () method returns a reference to the corresponding string in the constant pool if the value of String already exists. Instead, add the value contained in this String to the constant pool and return a reference to this String object. In JDK 1.6 and earlier, constant pools were allocated in permanent generations, so we can indirectly limit the size of constant pools by setting the parameters "-XX :PermSize" and "-ES64en :MaxPermSize".

Note that the memory distribution for the String.intern () method and the constant pool mentioned above is only for versions of JDK 1.6 and before, in versions of JDK 1.7 or above, the memory layout is slightly different due to the removal of the concept of permanent generations.

Here is an example of code that implements a constant pool memory overflow:


/**
 * @author xiongyongshun
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M 
 */
public class RuntimeConstantPoolOOMTest {
  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    int i = 0;
    while (true) {
      list.add(String.valueOf(i++).intern());
    }
  }
}

We see that in this example, it is the String.intern () method that is used to add a large number of string constants to the constant pool, thus causing the constant pool to overflow.

We compile and run the above code through JDK1.6, and the output is as follows:


Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
    at java.lang.String.intern(Native Method)
    at com.test.RuntimeConstantPoolOOMTest.main(RuntimeConstantPoolOOMTest.java:16)

It is important to note that if you run the above code through JDK1.8, you will get the following warning, and no exceptions will occur:


>>> java -XX:PermSize=10M -XX:MaxPermSize=10M com.test.RuntimeConstantPoolOOMTest                                                 16-10-03 0:23
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; support was removed in 8.0

The method area is out of memory

The method area is used to store Class information such as class name, class access modifier, field description, method description, etc. So if the method area is too small and too many classes are loaded, it can cause the method area to overflow.


//VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
public class MethodAreaOOMTest {
  public static void main(String[] args) {
    while (true) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(MethodAreaOOMTest.class);
      enhancer.setUseCache(false);
      enhancer.setCallback(new MethodInterceptor() {
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
          return methodProxy.invokeSuper(o, objects);
        }
      });

      enhancer.create();
    }
  }
}

In the above code, we use CGlib to dynamically generate a large number of classes. Under JDK6, running the above code will generate the exception OutOfMemoryError: PermGen space:


/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/bin/java -jar -XX:PermSize=10M -XX:MaxPermSize=10M target/Test-1.0-SNAPSHOT.jar

The output results are as follows:


>>> java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError com.test.OutOfMemoryErrorTest                                              16-10-02 23:35
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid1810.hprof ...
Heap dump file created [14212861 bytes in 0.125 secs]
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 com.test.OutOfMemoryErrorTest.main(OutOfMemoryErrorTest.java:15)
0

MetaSpace is out of memory

In the Method area Memory Overflow 1 section, we mentioned that JDK8 does not have the concept of permanent generations, so those two examples did not achieve the desired effect under JDK8. Under JDK8, are there any errors like method area memory overflow? Of course there is. In JDK8, the MetaSpace area is used to hold Class information, so when MetaSpace runs out of memory, the ES117en.lang.OutOfMemoryError: Metaspace exception is thrown.

Let's take the example mentioned above:


>>> java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError com.test.OutOfMemoryErrorTest                                              16-10-02 23:35
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid1810.hprof ...
Heap dump file created [14212861 bytes in 0.125 secs]
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 com.test.OutOfMemoryErrorTest.main(OutOfMemoryErrorTest.java:15)
1

The code for this example has not changed, except that the only difference is that we need to use JDK8 to run this code and set the parameter -ES127en :MaxMetaspaceSize=10M, which tells JVM Metaspace that the maximum size is 10M.

Then we use JDK8 to compile and run the example, and output the following exception:


>>> java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError com.test.OutOfMemoryErrorTest                                              16-10-02 23:35
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid1810.hprof ...
Heap dump file created [14212861 bytes in 0.125 secs]
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 com.test.OutOfMemoryErrorTest.main(OutOfMemoryErrorTest.java:15)
2

conclusion

That's the end of this article on common memory overflow exceptions and code examples for Java programming, and I hope you found them helpful. Interested friends can continue to refer to other related topics in this site, if there is any deficiency, welcome to comment out. Thank you for your support!


Related articles: