JVM direct memory
如果使用Java自带的 ByteBuffer.allocateDirect(size) 或者直接 new DirectByteBuffer(capacity) , 这样受-XX:MaxDirectMemorySize 这个JVM参数的限制. 其实底层都是用的Unsafe#allocateMemory,区别是对大小做了限制. 如果超出限制直接OOM.
Unsafe.allocateMemory
如果通过反射的方式拿到Unsafe的实例,然后用Unsafe的allocateMemory方法分配堆外内存. 确实不受-XX:MaxDirectMemorySize这个JVM参数的限制 . 所以限制的内存大小为操作系统的内存.
// 启动参数: -Xmx20M -XX:MaxDirectMemorySize=10M
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
}
}
}
这个代码并不产生异常
ByteBuffer.allocateDirect
如果不设置-XX:MaxDirectMemorySize 默认的话,是跟堆内存大小保持一致. [堆内存大小如果不设置的话,默认为操作系统的 1/4, 所以 DirectMemory的大小限制JVM的Runtime.getRuntime().maxMemory()内存大小
public class DirectMemoryOOM {
// 分配直接内存大小为 20M
private static final int size = 1024 * 1024*20;
// 启动参数: -Xmx20M -XX:MaxDirectMemorySize=10M -XX:+HeapDumpOnOutOfMemoryError
public static void main(String[] args) throws Exception {
ByteBuffer.allocateDirect(size);
}
}
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 com.jts.jvm.gc.oom.DirectMemoryOOM.main(DirectMemoryOOM.java:16)