2015-04-17 120 views
9

下面的代码将分配的直接内存大大小,但不会导致java.lang.OutOfMemoryError:直接缓冲存储器为什么XX:MaxDirectMemorySize不能限制Unsafe.allocateMemory?

//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:直接缓冲存储器。 我已经看到了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); 
     } 
    } 
} 

为什么限制无法发生的第一个实施?

回答

7

正如原来的答案所说:Unsafe.allocateMemory()是一个围绕os::malloc的包装,它不关心VM施加的任何内存限制。

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

+0

感谢您的回答! –

1

错误来自Bits.reserveMemory,在调用allocateDirect时调用unsafe.allocateMemory(size)之前调用该错误。

reserveMemory方法procceed此验证:

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

的引发错误,如果期望的分配是高于从

maxMemory = VM.maxDirectMemory(); 

调用allocateMemory检索到的maxMemory直接将进行本地方法并获得” t验证最大容量(这解释了为什么你不会在你的第一个片段中得到错误),这是--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

// These methods should be called whenever direct memory is allocated or 
// freed. They allow the user to control the amount of direct memory 
// which a process may access. All sizes are specified in bytes. 
static void reserveMemory(long size, int cap) {