为什么XX:MaxDirectMemorySize不能限制Unsafe.allocateMemory?

时间:2015-04-17 14:28:23

标签: java memory-management

下面的代码将分配大量的直接内存但不会导致 java.lang.OutOfMemoryError:直接缓冲内存

//JVM args: -Xms10m -Xmx10m -XX:MaxDirectMemorySize=10m
    public class DirectMemoryOOM {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            Field f = Unsafe.class.getDeclaredFields()[0];
            f.setAccessible(true);
            Unsafe us = (Unsafe) f.get(null);
            long size = 1024 * 1024 * 1024;
            while (true) {
                long p = us.allocateMemory(size);
                for (int i = 0; i < size; i++) {
                    us.putByte(p + i, Byte.MAX_VALUE);
                }
            }
        }
    }

但是代码后面的代码将获得 java.lang.OutOfMemoryError:Direct buffer memory 。 我从Java unsafe memory allocation limit看到了答案,但ByteBuffer.allocateDirect是使用Unsafe.allocateMemory()

实现的。
//JVM args: -Xms10m -Xmx10m -XX:MaxDirectMemorySize=10m
public class DirectMemoryOOM {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        int size = 1024 * 1024;
        System.out.println(sun.misc.VM.maxDirectMemory());
        while (true) {
            ByteBuffer.allocateDirect(size);
        }
    }
}

为什么限制失败发生在第一个?

2 个答案:

答案 0 :(得分:7)

正如原始答案所说:Unsafe.allocateMemory()os::malloc的包装器,它不关心VM强加的任何内存限制。

ByteBuffer.allocateDirect()将调用此方法,但在此之前,它将调用Bits.reserveMemory()(在我的Java 7版本中:DirectByteBuffer.java:123),它会检查进程的内存使用情况并抛出异常你提到的。

答案 1 :(得分:1)

错误来自Bits.reserveMemoryunsafe.allocateMemory(size)在调用allocateDirect时调用{。}}。

reserveMemory方法获得了此验证:

synchronized (Bits.class) {
    if (totalCapacity + cap > maxMemory)
        throw new OutOfMemoryError("Direct buffer memory");
    reservedMemory += size;
    totalCapacity += cap;
    count++;
}

如果所需分配高于从

检索到的maxMemory,则会引发错误
maxMemory = VM.maxDirectMemory();

直接拨打allocateMemory将继续使用原生方法并且无法验证最大容量(这可以解释您为什么不在第一个代码段中收到错误),这是{的主要目标{1}}正如--XX:MaxDirectMemorySize

中的评论中所解释的那样
reserveMemory

值得一提的是,您的第一个代码段实现并不是一个好习惯。 // -XX:MaxDirectMemorySize limits the total capacity rather than the // actual memory usage, which will differ when buffers are page // aligned. if (cap <= maxMemory - totalCapacity) { reservedMemory += size; totalCapacity += cap; count++; return; } 中的注释指定在分配直接内存时应始终调用Bits.java

reserveMemory