ホームページ  >  記事  >  Java  >  Java の共通メモリ オーバーフロー例外とコードの実装

Java の共通メモリ オーバーフロー例外とコードの実装

黄舟
黄舟オリジナル
2017-02-23 10:38:041437ブラウズ

Java Heap OutOfMemoryError

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 stack StackOverflowError

のランタイム データ領域に仮想マシン スタックと呼ばれるメモリ領域があることがわかります。 JVM この領域の役割は次のとおりです: 各メソッド 実行中にローカル変数テーブル、オペランド スタック、メソッド出口などの情報を保存するためのスタック フレームが作成されます。大きすぎると、スタックが枯渇し、StackOverflowError 例外が発生します。

具体的なコードは次のとおりです。


>>> 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)



ランタイム定数プールのオーバーフロー

Java 1.6および以前のHotSpot JVMバージョンには、永続世代の概念があります。つまり、GCの世代別コレクションメカニズムが拡張されています。メソッド領域では、メモリの一部が定数プールの格納に使用されるため、コード内に定数が多すぎると、定数プールのメモリが枯渇し、メモリ オーバーフローが発生します。定数プールに多数の定数を追加するには、String.intern() String メソッドを使用する必要があります。この String の値が定数プールにすでに存在する場合。の場合、このメソッドは定数プール内の対応する文字列への参照を返します。それ以外の場合、この String に含まれる値が定数プールに追加され、この Reference to String オブジェクトが返されます。JDK 1.6 以前のバージョンでは、定数プールは に割り当てられます。永続的な世代なので、パラメーター "-XX:PermSize" と "-XX:MaxPermSize" を設定することで、定数プールのサイズを間接的に制限できます。


, 因为 JDK8 已经移除了永久代, 取而代之的是 metaspace, 因此在 JDK8 中, 下面两个例子都不会导致 java.lang.OutOfMemoryError: PermGen space 异常.

以下は、定数プール メモリを実装するコード例です。 overflow:



, 上面所说的 String.intern() 方法和常量池的内存分布仅仅针对于 JDK 1.6 及之前的版本, 在 JDK 1.7 或以上的版本中, 由于去除了永久代的概念, 因此内存布局稍有不同.
この例では、String.intern() メソッドを使用して定数プール定数に多数の文字列が追加され、その結果定数プールでメモリ オーバーフローが発生していることがわかります。上記のコードを JDK1.6 で実行すると、次の出力が得られます:



/**
 * @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

上記のコードでは、CGlibを​​使用しています。多数のクラスを動的に生成するには、JDK6 で上記のコードを実行すると、OutOfMemoryError: PermGen スペース例外が生成されます:

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

出力結果は次のとおりです:



//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();
        }
    }
}

MetaSpaceメモリオーバーフロー


「メソッド領域のメモリオーバーフロー」セクションで、次のように述べました。 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

例は変更されていません。唯一の違いは、このコードを実行するために JDK8 を使用し、パラメーター -XX:MaxMetaspaceSize=10M を設定する必要があることです。このパラメーターは、メタスペースの最大サイズが 10M であることを JVM に伝えます。 JDK8 を使用してこの例をコンパイルして実行すると、次の例外が出力されます:

//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)!






-->


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。