Java直接內存與堆內存


NIO的Buffer提供了一個可以不經過JVM內存直接訪問系統物理內存的類——DirectBuffer。 DirectBuffer類繼承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配內存,其最大內存受到最大堆內存的限制;而DirectBuffer直接分配在物理內存中,並不占用堆空間,其可申請的最大內存受操作系統限制。

直接內存的讀寫操作比普通Buffer快,但它的創建、銷毀比普通Buffer慢(猜測原因是DirectBuffer需向OS申請內存涉及到用戶態內核態切換,而后者則直接從堆內存划內存即可)。

因此直接內存使用於需要大內存空間且頻繁訪問的場合,不適用於頻繁申請釋放內存的場合。

 

(Note:DirectBuffer並沒有真正向OS申請分配內存,其最終還是通過調用Unsafe的allocateMemory()來進行內存分配。不過JVM對Direct Memory可申請的大小也有限制,可用-XX:MaxDirectMemorySize=1M設置,這部分內存不受JVM垃圾回收管理。

 

使用對外內存的原因:

  • 對垃圾回收停頓的改善。由於堆外內存是直接受操作系統管理而不是JVM,所以當我們使用堆外內存時,即可保持較小的堆內內存規模。從而在GC時減少回收停頓對於應用的影響。
  • 提升程序I/O操作的性能。通常在I/O通信過程中,會存在堆內內存到堆外內存的數據拷貝操作,對於需要頻繁進行內存間數據拷貝且生命周期較短的暫存數據,都建議存儲到堆外內存。

 

 

 

以下是一些測試:

代碼:

 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 }
View Code

結果:

訪問性能測試:
access_nondirect:157
access_direct:134

分配性能測試:
allocate_nondirect:231
allocate_direct:613

可見與在JVM堆分配內存(allocate)相比,直接內存分配(allocateDirect)的訪問性能更好,但分配較慢。(一般如此,當然數據量小的話差別不是那么明顯)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM