2015-04-17 14 views
9

Il seguente codice attribuisce una grande dimensione di memoria diretta ma non causare java.lang.OutOfMemoryError: memoria buffer diretto:Perché XX: MaxDirectMemorySize non può limitare 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); 
       } 
      } 
     } 
    } 

Ma il codice seguente codice otterrà java.lang.OutOfMemoryError: Memoria buffer diretta. Ho visto la risposta da Java unsafe memory allocation limit, ma ByteBuffer.allocateDirect è implementato utilizzando 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); 
     } 
    } 
} 

Perché il limite non riescono succede al primo?

risposta

7

Come dice la risposta originale: Unsafe.allocateMemory() è un wrapper attorno a os::malloc che non interessa i limiti di memoria imposti dalla VM.

ByteBuffer.allocateDirect() chiamerà questo metodo, ma prima di questo, si chiamerà Bits.reserveMemory() (Nella mia versione di Java 7: DirectByteBuffer.java:123) che controlla l'utilizzo della memoria del processo e genera l'eccezione che si parla.

+0

Grazie per la risposta! –

1

L'errore viene da Bits.reserveMemory che viene chiamato prima dello unsafe.allocateMemory(size) quando si chiama allocateDirect.

Il metodo reserveMemory procceed questa convalida:

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

L'errore viene generato se l'allocazione desiderata è superiore alla maxMemory recuperato da

maxMemory = VM.maxDirectMemory(); 

Calling allocateMemory direttamente procederà metodo nativo e ha vinto' t convalidare la capacità massima (che spiega perché non si ottiene l'errore nel primo frammento di codice) che è l'obiettivo principale di --XX:MaxDirectMemorySize come spiegato in questo commento in 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; 
} 

pena ricordare che la prima implementazione frammento non è una buona pratica. Un commento in Bits.java specificare che reserveMemory dovrebbe sempre essere chiamato ogni volta che viene allocata memoria diretta:

// 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) { 
Problemi correlati