前言
直接記憶體大多時候也被稱為堆外記憶體,自從 JDK 引入 NIO 後,直接記憶體的使用也越來越普遍。通過 native 方法可以分配堆外記憶體,通過 DirectByteBuffer 物件來操作。
直接記憶體不屬於 Java 堆,所以它不受堆大小限制,但是它受實體記憶體大小的限制。
配置
可以通過 -XX:MaxDirectMemorySize 引數來設定最大可用直接記憶體,如果啟動時未設定則預設為最大堆記憶體大小,即與 -Xmx 相同。即假如最大堆記憶體為1G,則預設直接記憶體也為1G,那麼 JVM 最大需要的記憶體大小為2G多一些。當直接記憶體達到最大限制時就會觸發GC,如果回收失敗則會引起OutOfMemoryError。
分配記憶體耗時
環境為JDK9,兩種記憶體分配的耗時如下,執行兩遍讓其預熱。可以看到直接記憶體的分配比較耗時,而堆記憶體分配操作耗時少好幾倍。
public static void directMemoryAllocate() {
long tsStart = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
ByteBuffer buffer = ByteBuffer.allocateDirect(400);
}
System.out.println("direct memory allocate: " + (System.currentTimeMillis() - tsStart) + " ms");
tsStart = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
ByteBuffer buffer = ByteBuffer.allocate(400);
}
System.out.println("heap memory allocate: " + (System.currentTimeMillis() - tsStart) + " ms");
}
複製程式碼
direct memory allocate: 149 ms
heap memory allocate: 41 ms
direct memory allocate: 122 ms
heap memory allocate: 31 ms
複製程式碼
讀寫操作耗時
環境為JDK9,兩種記憶體的讀寫操作耗時如下,同樣執行兩遍讓其預熱,可以看到直接記憶體讀寫操作的速度相對快一些。
public static void memoryRW() {
ByteBuffer buffer = ByteBuffer.allocateDirect(400);
ByteBuffer buffer2 = ByteBuffer.allocate(400);
long tsStart = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
for (int j = 0; j < 100; j++) {
buffer.putInt(j);
}
buffer.flip();
for (byte j = 0; j < 100; j++) {
buffer.getInt();
}
buffer.clear();
}
System.out.println("direct memory rw: " + (System.currentTimeMillis() - tsStart) + " ms");
tsStart = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
for (int j = 0; j < 100; j++) {
buffer2.putInt(j);
}
buffer2.flip();
for (byte j = 0; j < 100; j++) {
buffer2.getInt();
}
buffer2.clear();
}
System.out.println("heap memory rw: " + (System.currentTimeMillis() - tsStart) + " ms");
}
複製程式碼
direct memory rw: 39 ms
heap memory rw: 34 ms
direct memory rw: 23 ms
heap memory rw: 46 ms
複製程式碼
總結
理論上直接記憶體的機制訪問速度要快一些,但也不能武斷地直接說直接記憶體快,另外,在記憶體分配操作上直接記憶體要慢一些。直接記憶體更適合在記憶體申請次數較少,但讀寫操作較頻繁的場景。
-------------推薦閱讀------------
跟我交流,向我提問:
公眾號的選單已分為“讀書總結”、“分散式”、“機器學習”、“深度學習”、“NLP”、“Java深度”、“Java併發核心”、“JDK原始碼”、“Tomcat核心”等,可能有一款適合你的胃口。
歡迎關注: