Java ヒープはオブジェクト インスタンスの保存に使用されるため、継続的にオブジェクトを作成し、オブジェクトがガベージ コレクションされないように GC ルートと作成されたオブジェクトの間に到達可能なパスがあることを確認すると、作成されたオブジェクトが通過すると、時間が経つとヒープのメモリが不足し、OutOfMemoryError 例外が発生します。上記は OutOfMemoryError 例外を引き起こすコードです。オブジェクトを継続的に作成してリストに保存するため、オブジェクトが多すぎるとヒープ メモリがオーバーフローします。
java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError を通じてヒープ メモリを 10 MB に設定し、パラメータ -XX:+HeapDumpOnOutOfMemoryError を使用して、OutOfMemoryError 例外が発生したときに JVM が現在のメモリ スナップショットを出力できるようにし、後続の分析に使用します。
上記のコードをコンパイルして実行すると、次の出力が得られます:
/** * @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++); } } }
>>> 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)
/** * @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 异常.
, 上面所说的 String.intern() 方法和常量池的内存分布仅仅针对于 JDK 1.6 及之前的版本, 在 JDK 1.7 或以上的版本中, 由于去除了永久代的概念, 因此内存布局稍有不同.
/** * @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()); } } }
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
//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(); } } }
「メソッド領域のメモリオーバーフロー」セクションで、次のように述べました。 JDK8 には永続的な生成の概念がないため、これら 2 つの例は JDK8 では期待どおりの結果を達成できませんでした。JDK8 では、メソッド領域のメモリ オーバーフローなどのエラーはありますか? もちろん、JDK8 では MetaSpace 領域が使用されます。クラス関連の情報を格納するため、MetaSpace のメモリ領域が不十分な場合、 java.lang.OutOfMemoryError: Metaspace 例外がスローされます
例として上記の例を見てみましょう:
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
//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(); } } }
上記は、一般的な Java メモリ オーバーフロー例外とコード実装の内容です。詳細については、PHP 中国語 Web サイト (www. php.cn)!