The Java heap is used to store object instances, so if we continue to create objects and ensure that there is a reachable path between the GC Root and the created object to prevent the object from being garbage collected, Then when too many objects are created, it will cause insufficient memory in the heap, which will trigger 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++); } } }
The above is a code that triggers an OutOfMemoryError exception. We can see that it continuously Create objects independently and save the objects in the list to prevent them from being garbage collected. Therefore, when there are too many objects, the heap memory will overflow.
Through java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError we set the heap memory to 10 MB, and use the parameter -XX:+HeapDumpOnOutOfMemoryError to let the JVM print out the current memory snapshot when an OutOfMemoryError exception occurs for subsequent convenience Analysis.
After compiling and running the above code, there will be the following output:
>>> 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)
We know that the runtime data area of the JVM There is a memory area called the virtual machine stack. The role of this area is: each method will create a stack frame when executed, which is used to store local variable tables, operand stacks, method exits and other information.
So we can create an infinitely recursive recursive call. When the recursion depth is too large, the stack space will be exhausted, which will lead to a StackOverflowError exception.
The following is the specific 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 message will be output:
Exception in thread "main" java.lang.StackOverflowError at com.test.OutOfMemoryErrorTest.stackOutOfMemoryError(OutOfMemoryErrorTest.java:27)
, 因为 JDK8 已经移除了永久代, 取而代之的是 metaspace, 因此在 JDK8 中, 下面两个例子都不会导致 java.lang.OutOfMemoryError: PermGen space 异常.
In Java 1.6 and previous HotSpot JVM versions, there is the concept of the permanent generation, that is, the generational collection mechanism of GC is extended to the method area. In the method area , a part of the memory is used to store the constant pool, so if there are too many constants in the code, the constant pool memory will be exhausted, leading to memory overflow. So how to add a large number of constants to the constant pool? At this time, you need to rely on String. intern() method. The function of String.intern() method is: if the value of this String already exists in the constant pool, this method returns the reference of the corresponding string in the constant pool; otherwise, the value contained in this String is added. to the constant pool, and returns a reference to this String object. In JDK 1.6 and previous versions, the constant pool is allocated in the permanent generation, so we can set the parameters "-XX:PermSize" and "-XX:MaxPermSize" to Indirectly limit the size of the constant pool.
, 上面所说的 String.intern() 方法和常量池的内存分布仅仅针对于 JDK 1.6 及之前的版本, 在 JDK 1.7 或以上的版本中, 由于去除了永久代的概念, 因此内存布局稍有不同.
The following is a code example to implement 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 , in this example, the String.intern() method is used to add a large number of string constants to the constant pool, thus causing the memory overflow of the constant pool.
We compile and compile through JDK1.6 Running the above code, there will be the following output:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.String.intern(Native Method) at com.test.RuntimeConstantPoolOOMTest.main(RuntimeConstantPoolOOMTest.java:16)
, 如果通过 JDK1.8 来编译运行上面代码的话, 会有如下警告, 并且不会产生任何的异常:
>>> 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 used to store Class-related information, such as class name, class access Modifiers, field descriptions, method descriptions, etc. Therefore, if the method area is too small and too many classes are loaded, the memory in the method area will 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 an OutOfMemoryError: PermGen space exception:
/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:
Caused by: java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:637) at java.lang.ClassLoader.defineClass(ClassLoader.java:621) ... 11 more
In the section Memory Overflow in the Method Area, we mentioned that JDK8 does not have the concept of permanent generation, so the two examples did not achieve the expected results under JDK8. So under JDK8, whether Are there errors like memory overflow in the method area? Of course there are. In JDK8, the MetaSpace area is used to store Class-related information, so when the MetaSpace memory space is insufficient, java.lang.OutOfMemoryError: Metaspace will be thrown Exception.
We still take the example mentioned above as an example:
//VM Args: -XX:MaxMetaspaceSize=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(); } } }
The code part of this example has not been changed, the only difference is that we need to use JDK8 to run This code is set with the parameter -XX:MaxMetaspaceSize=10M. This parameter tells the JVM that the maximum size of Metaspace is 10M.
Then we use JDK8 to compile and run this example, and the following exception is output:
>>> java -jar -XX:MaxMetaspaceSize=10M target/Test-1.0-SNAPSHOT.jar Exception in thread "main" java.lang.OutOfMemoryError: Metaspace at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345) at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492) at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:114) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291) at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305) at com.test.MethodAreaOOMTest.main(MethodAreaOOMTest.java:22)
The above is the content of common Java memory overflow exceptions and code implementation. For more related content, please pay attention to the PHP Chinese website (m.sbmmt.com)!