Jvm の各パーティションの OOM を回避する方法を見つける
ヒープメモリ#
ヒープメモリのオーバーフローは、オブジェクトを継続的に作成し、GC によって回収されない(到達性分析、GC ルートとオブジェクトの間に到達可能なパスがある)場合に発生します。
パラメータ:-Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError
byte[] a = new byte[21 * 1024 * 1024];
HeapDumpOnOutOfMemoryError
を追加すると、ログをダンプして後続の OOM の問題を分析しやすくなります。
スタックメモリのオーバーフロー#
仮想マシンのスタックには、ローカル変数テーブルがあり、ローカル変数を継続的に作成することでオーバーフローさせることができます。
(ここでは OOM に成功しませんでしたが、それが Jvm の原因なのか何なのかわかりません)
パラメータ:-Xss1m -XX:+HeapDumpOnOutOfMemoryError
public void StackOOM() {
while (true) {
Thread thread = new Thread(this::job);
thread.start();
}
}
private void job() {
while (true) {
}
}
メソッド領域のオーバーフロー#
メソッド領域はクラスの情報を格納するために使用されるため、メソッド領域をオーバーフローさせるには、大量のクラスを動的に生成するだけです。クラスを生成するための比較的簡単な方法は、Cglib を使用することです。
Cglib を使用しているプロジェクトでは、メソッド領域のオーバーフローの例外が発生する可能性があります。たとえば、Spring の Aop では、多くの増強クラスが生成されると、多くのクラスが生成され、メソッド領域のサイズが不足すると例外が発生します。
-XX:PermSize=1M -XX:MaxPermSize=1M
を使用する場合は、jvm のバージョンが 8 未満であることを確認してください。なぜなら、Java1.8 では永久代が削除され、クラス情報が Meta Space に配置されるからです。
Meta Space の制御には、-XX:MetaspaceSize
と-XX:MaxMetaspaceSize
を使用します。
パラメータ:-XX=10m -XX=10m -Xmx20m -Xms10m
while (true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TestMain.class);
enhancer.setUseCache(false);
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects));
enhancer.create();
}
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
ダイレクトメモリのオーバーフロー#
ダイレクトメモリのオーバーフローは通常、Nio が発生する場所で発生します。たとえば、Netty です。unsafe メソッドを使用してシステムメモリを直接要求することで、ダイレクトメモリのオーバーフローをシミュレートできます。
パラメータ:-XX=10M -XX:+HeapDumpOnOutOfMemoryError
Field field = Unsafe.class.getDeclaredFields()[0];
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
while (true) {
unsafe.allocateMemory(1 * 1024 * 1024);
}
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)