jvm 内存溢出-直接内存溢出

jvm 内存溢出-直接内存溢出

DirectMemory 容量可通过 -XX:MaxDirectMemorySize 指定,如果不指定,则默认与 Java 堆最大值( -Xmx 指定)一样,下面程序利用 DirectByteBuffe 模拟直接内存溢出的情况

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class DirectBufferOom {
  public static void main(String[] args) {
    final int _1M = 1024 * 1024;
    List<ByteBuffer> buffers = new ArrayList<>();
    int count = 1;
    while (true) {
      ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1M);
      buffers.add(byteBuffer);
      System.out.println(count++);
    }
  }
}

在命令行运行 java -XX:MaxDirectMemorySize=10M DirectBufferOom ,很快控制台就会出现异常

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
    at java.nio.Bits.reserveMemory(Bits.java:695)
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
    at DirectBufferOom.main(DirectBufferOom.java:12)

其实它并没有真正向操作系统申请分配内存,而是通过计算得知内存无法分配,于是手动抛出异常。下面的程序利用 Unsafe 类模拟直接内存溢出

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class UnsafeOom {
  private static final int _1M = 1024 * 1024;

  public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
    Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
    unsafeField.setAccessible(true);
    Unsafe unsafe = (Unsafe) unsafeField.get(null);
    while (true) {
      unsafe.allocateMemory(_1M);
    }
  }
}

在命令行运行 java -XX:MaxDirectMemorySize=10M UnsafeOom ,结果如下

Exception in thread"main"java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at org.fenixsoft.oom.DMOOM.main(DMOOM.java:20)

由 DirectMemory 导致的内存溢出,一个明显的特征是在 Heap Dump 文件中不会看见明显的异常,如果读者发现 OOM 之后 Dump 文件很小,而程序中又直接或间接使用了 NIO ,那就可以考虑检查一下是不是这方面的原因。

猜你喜欢

转载自blog.csdn.net/a303549861/article/details/88718407