1. 程式人生 > 實用技巧 >JVM直接記憶體(Direct Memory)

JVM直接記憶體(Direct Memory)

直接記憶體

1.直接記憶體不是虛擬機器執行時資料區的一部分,也不是《Java虛擬機器規範》中定義的記憶體區域。

2.直接記憶體是Java堆外的、直接向系統申請的記憶體區間。

3.簡單理解: java process memory = java heap + native memory

示例程式碼:

/**
 *  IO                  NIO (New IO / Non-Blocking IO)
 *  byte[] / char[]     Buffer
 *  Stream              Channel
 *
 * 檢視直接記憶體的佔用與釋放
 */
public
class BufferTest { private static final int BUFFER = 1024 * 1024 * 1024;//1GB public static void main(String[] args){ //直接分配本地記憶體空間 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER); System.out.println("直接記憶體分配完畢,請求指示!"); Scanner scanner = new Scanner(System.in); scanner.next(); System.out.println(
"直接記憶體開始釋放!"); byteBuffer = null; System.gc(); scanner.next(); } }

直接記憶體來源於NIO

通過存在堆中的DirectByteBuffer操作Native記憶體。訪問直接記憶體的速度會優於Java堆。即讀寫效能高。

  • 因此出於效能考慮,讀寫頻繁的場合可能會考慮使用直接記憶體
  • Java的NIO庫允許Java程式使用直接記憶體,用於資料緩衝區

直接記憶體異常OOM

同樣,也可能導致OutOfMemoryError異常:OutOfMemoryError: Direct buffer memory

由於直接記憶體在Java堆外,因此它的大小不會直接受限於一Xmx指定的最大 堆大小,但是系統記憶體是有限的,Java堆和直接記憶體的總和依然受限於作業系統能給出的最大記憶體。

/**
 * 本地記憶體的OOM:  OutOfMemoryError: Direct buffer memory
 */
public class BufferTest2 {
    private static final int BUFFER = 1024 * 1024 * 20;//20MB

    public static void main(String[] args) {
        ArrayList<ByteBuffer> list = new ArrayList<>();

        int count = 0;
        try {
            while(true){
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
                list.add(byteBuffer);
                count++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            System.out.println(count);
        }


    }
}

直接記憶體引數設定

  • 使用直接記憶體的缺點
    • 分配回收成本較高
    • 不受JVM記憶體回收管理
  • 直接記憶體大小可以通過MaxDirectMemorySize設定
  • 如果不指定,預設與堆的最大值一Xmx引數值一致