下面的代码将分配大量的直接内存但不会导致 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);
}
}
}
为什么限制失败发生在第一个?
答案 0 :(得分:7)
正如原始答案所说:Unsafe.allocateMemory()
是os::malloc
的包装器,它不关心VM强加的任何内存限制。
ByteBuffer.allocateDirect()
将调用此方法,但在此之前,它将调用Bits.reserveMemory()
(在我的Java 7版本中:DirectByteBuffer.java:123
),它会检查进程的内存使用情况并抛出异常你提到的。
答案 1 :(得分:1)
错误来自Bits.reserveMemory
,unsafe.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