Der Java-Heap wird zum Speichern von Objektinstanzen verwendet. Wenn wir also weiterhin Objekte erstellen und sicherstellen, dass zwischen dem GC-Stamm und dem erstellten Objekt ein erreichbarer Pfad vorhanden ist, verhindern wir, dass das Objekt beschädigt wird Wenn zu viele Objekte erstellt werden, reicht der Heap-Speicher nicht aus, was zu einer OutOfMemoryError-Ausnahme führt.
/** * @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++); } } }
Das Obige ist ein Code, der einen OutOfMemoryError verursacht Ausnahme Wir können sehen, dass dies der Fall ist. Durch kontinuierliches Erstellen von Objekten und Speichern in einer Liste, um zu verhindern, dass sie durch Müll gesammelt werden, läuft der Heap-Speicher über, wenn zu viele Objekte vorhanden sind.
Mit java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError setzen wir den Heap-Speicher auf 10 MB und verwenden den Parameter -XX:+HeapDumpOnOutOfMemoryError, damit die JVM den aktuellen Speicher-Snapshot ausdrucken kann, wenn eine OutOfMemoryError-Ausnahme auftritt zur späteren praktischen Analyse.
Nach dem Kompilieren und Ausführen des obigen Codes wird die folgende Ausgabe angezeigt:
>>> 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)
Wir wissen, dass es in der Laufzeit von JVM einen Speicherbereich gibt, der als Stapel der virtuellen Maschine im Datenbereich bezeichnet wird. Die Rolle dieses Bereichs besteht darin, dass jede Methode bei der Ausführung einen Stapelrahmen erstellt, der zum Speichern lokaler Variablentabellen und Operandenstapel verwendet wird , Methodenexits und andere Informationen.
So können wir einen unendlich rekursiven Aufruf erstellen. Wenn die Rekursionstiefe zu groß ist, wird der Stapelspeicher erschöpft, was zu einer StackOverflowError-Ausnahme führt 🎜>Das Folgende ist der spezifische 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); } }
Exception in thread "main" java.lang.StackOverflowError at com.test.OutOfMemoryErrorTest.stackOutOfMemoryError(OutOfMemoryErrorTest.java:27)
, 因为 JDK8 已经移除了永久代, 取而代之的是 metaspace, 因此在 JDK8 中, 下面两个例子都不会导致 java.lang.OutOfMemoryError: PermGen space 异常.
Konstanter Poolüberlauf zur Laufzeit
, 上面所说的 String.intern() 方法和常量池的内存分布仅仅针对于 JDK 1.6 及之前的版本, 在 JDK 1.7 或以上的版本中, 由于去除了永久代的概念, 因此内存布局稍有不同.Das Folgende ist ein Codebeispiel zur Implementierung eines konstanten Pool-Speicherüberlaufs:
/** * @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()); } } }
Wir kompilieren das Obige und führen es aus Code über JDK1.6, und es wird die folgende Ausgabe angezeigt:
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 来编译运行上面代码的话, 会有如下警告, 并且不会产生任何的异常:Speicherüberlauf im Methodenbereich
>>> 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
//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(); } } }
/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/bin/java -jar -XX:PermSize=10M -XX:MaxPermSize=10M target/Test-1.0-SNAPSHOT. jar
Die Ausgabeergebnisse lauten wie folgt:
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
Nehmen wir das oben genannte Beispiel als Beispiel:
//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(); } } }
Dann verwenden wir JDK8, um dieses Beispiel zu kompilieren und auszuführen, und die folgende Ausnahme wird ausgegeben:
>>> 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)