JVM直接記憶體(Direct Memory)
阿新 • • 發佈:2020-07-18
直接記憶體
1.直接記憶體不是虛擬機器執行時資料區的一部分,也不是《Java虛擬機器規範》中定義的記憶體區域。
2.直接記憶體是Java堆外的、直接向系統申請的記憶體區間。
3.簡單理解: java process memory = java heap + native memory
示例程式碼:
/** * IO NIO (New IO / Non-Blocking IO) * byte[] / char[] Buffer * Stream Channel * * 檢視直接記憶體的佔用與釋放 */ publicclass 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引數值一致