Java直接內存和堆內存誰快

前言

直接內存大多時候也被稱為堆外內存,自從 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 msheap memory allocate: 41 msdirect memory allocate: 122 msheap 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 msheap memory rw: 34 msdirect memory rw: 23 msheap memory rw: 46 ms

總結

理論上直接內存的機制訪問速度要快一些,但也不能武斷地直接說直接內存快,另外,在內存分配操作上直接內存要慢一些。直接內存更適合在內存申請次數較少,但讀寫操作較頻繁的場景。

Java直接內存和堆內存誰快


分享到:


相關文章: