Java直接記憶體與堆記憶體
阿新 • • 發佈:2018-11-11
NIO的Buffer提供了一個可以不經過JVM記憶體直接訪問系統實體記憶體的類——DirectBuffer。 DirectBuffer類繼承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配記憶體,其最大記憶體受到最大堆記憶體的限制;而DirectBuffer直接分配在實體記憶體中,並不佔用堆空間,其可申請的最大記憶體受作業系統限制。
直接記憶體的讀寫操作比普通Buffer快,但它的建立、銷燬比普通Buffer慢。
因此直接記憶體使用於需要大記憶體空間且頻繁訪問的場合,不適用於頻繁申請釋放記憶體的場合。
(Note:DirectBuffer並沒有真正向OS申請分配記憶體,其最終還是通過呼叫Unsafe的allocateMemory()來進行記憶體分配。不過JVM對Direct Memory可申請的大小也有限制,可用-XX:MaxDirectMemorySize=1M設定,這部分記憶體不受JVM垃圾回收管理。)
以下是一些測試:
程式碼:
1 class DirectMemory { 2 3 // 分配堆記憶體 4 public static void bufferAccess() { 5 long startTime = System.currentTimeMillis(); 6 ByteBuffer b = ByteBuffer.allocate(500); 7 for (int i = 0; i < 1000000; i++) { 8 for (int j = 0; j < 99; j++) 9 b.putInt(j); 10 b.flip(); 11 for (int j = 0; j < 99; j++) 12 b.getInt(); 13 b.clear(); 14 } 15 long endTime = System.currentTimeMillis(); 16 System.out.println("access_nondirect:" + (endTime - startTime)); 17 } 18 19 // 直接分配記憶體 20 public static void directAccess() { 21 long startTime = System.currentTimeMillis(); 22 ByteBuffer b = ByteBuffer.allocateDirect(500); 23 for (int i = 0; i < 1000000; i++) { 24 for (int j = 0; j < 99; j++) 25 b.putInt(j); 26 b.flip(); 27 for (int j = 0; j < 99; j++) 28 b.getInt(); 29 b.clear(); 30 } 31 long endTime = System.currentTimeMillis(); 32 System.out.println("access_direct:" + (endTime - startTime)); 33 } 34 35 public static void bufferAllocate() { 36 long startTime = System.currentTimeMillis(); 37 for (int i = 0; i < 1000000; i++) { 38 ByteBuffer.allocate(1000); 39 } 40 long endTime = System.currentTimeMillis(); 41 System.out.println("allocate_nondirect:" + (endTime - startTime)); 42 } 43 44 public static void directAllocate() { 45 long startTime = System.currentTimeMillis(); 46 for (int i = 0; i < 1000000; i++) { 47 ByteBuffer.allocateDirect(1000); 48 } 49 long endTime = System.currentTimeMillis(); 50 System.out.println("allocate_direct:" + (endTime - startTime)); 51 } 52 53 public static void main(String args[]) { 54 System.out.println("訪問效能測試:"); 55 bufferAccess(); 56 directAccess(); 57 58 System.out.println(); 59 60 System.out.println("分配效能測試:"); 61 bufferAllocate(); 62 directAllocate(); 63 } 64 }
結果:
訪問效能測試: access_nondirect:157 access_direct:134 分配效能測試: allocate_nondirect:231 allocate_direct:613
可見與在JVM堆分配記憶體(allocate)相比,直接記憶體分配(allocateDirect)的訪問效能更好,但分配較慢。(一般如此,當然資料量小的話差別不是那麼明顯)