NIO之直接緩衝區與非直接緩衝區

直接緩衝區與非直接緩衝區的概念

1、非直接緩衝區

1)建立方式

經過html

static ByteBuffer allocate(int capacity)

建立的緩衝區,在JVM中內存中建立,在每次調用基礎操做系統的一個本機IO以前或者以後,虛擬機都會將緩衝區的內容複製到中間緩衝區(或者從中間緩衝區複製內容),緩衝區的內容駐留在JVM內,所以銷燬容易,可是佔用JVM內存開銷,處理過程當中有複製操做。java

2)寫入步驟數組

1.建立一個臨時的直接ByteBuffer對象。
2.將非直接緩衝區的內容複製到臨時緩衝中。
3.使用臨時緩衝區執行低層次I/O操做。
4.臨時緩衝區對象離開做用域,並最終成爲被回收的無用數據。app

2、直接緩衝區

1)建立方式

經過jvm

static ByteBuffer allocateDirect(int capacity)

建立的緩衝區,在JVM內存外開闢內存,在每次調用基礎操做系統的一個本機IO以前或者以後,虛擬機都會避免將緩衝區的內容複製到中間緩衝區(或者從中間緩衝區複製內容),緩衝區的內容駐留在物理內存內,會少一次複製過程,若是須要循環使用緩衝區,用直接緩衝區能夠很大地提升性能。雖然直接緩衝區使JVM能夠進行高效的I/O操做,但它使用的內存是操做系統分配的,繞過了JVM堆棧,創建和銷燬比堆棧上的緩衝區要更大的開銷。性能

直接緩衝區與非直接緩衝區的區別

  1. 字節緩衝區要麼是直接的,要麼是非直接的。若是爲直接字節緩衝區,則 Java 虛擬機會盡最大努力直接在此緩衝區上執行本機 I/O 操做。也就是說,在每次調用基礎操做系統的一個本機 I/O 操做以前(或以後),虛擬機都會盡可能避免將緩衝區的內容複製到中間緩衝區中(或從中間緩衝區中複製內容)。
  2. 直接字節緩衝區能夠經過調用此類的 allocateDirect() 工廠方法來建立。此方法返回的緩衝區進行分配和取消分配所需成本一般高於非直接緩衝區。直接緩衝區的內容能夠駐留在常規的垃圾回收堆以外,所以,它們對應用程序的內存需求量形成的影響可能並不明顯。因此,建議將直接緩衝區主要分配給那些易受基礎系統的本機 I/O 操做影響的大型、持久的緩衝區。通常狀況下,最好僅在直接緩衝區能在程序性能方面帶來明顯好處時分配它們。
  3. 直接字節緩衝區還能夠經過 FileChannel 的 map() 方法 將文件區域直接映射到內存中來建立。該方法返回MappedByteBuffer 。 Java 平臺的實現有助於經過 JNI 從本機代碼建立直接字節緩衝區。若是以上這些緩衝區中的某個緩衝區實例指的是不可訪問的內存區域,則試圖訪問該區域不會更改該緩衝區的內容,而且將會在訪問期間或稍後的某個時間致使拋出不肯定的異常。
  4. 字節緩衝區是直接緩衝區仍是非直接緩衝區可經過調用其 isDirect() 方法來肯定。提供此方法是爲了可以在性能關鍵型代碼中執行顯式緩衝區管理。

直接緩衝區與非直接緩衝區區別圖形示意

物理磁盤->內核地址空間->用戶地址空間->應用程序
OS                              ->                           JVM

直接緩衝區:內核地址空間和用戶地址空間之間造成了一個物理內存映射文件,減小了之間的copy過程。spa

這邊能夠看下jvm結構裏的直接內存:JVM虛擬機(一):java虛擬機的基本結構操作系統

代碼示例

  1 package com.expgiga.NIO;
  2 
  3 import java.nio.ByteBuffer;
  4 
  5 /**
  6  * 1、緩衝區(Buffer):在Java NIO中負責數據的存取,緩衝區就是數組,用於存儲不一樣數據類型的數據。
  7  * 根據數據類型不一樣(boolean除外),提供了相應類型的緩衝區
  8  *
  9  * ByteBuffer
 10  * CharBuffer
 11  * ShortBuffer
 12  * IntBuffer
 13  * LongBuffer
 14  * FloatBuffer
 15  * DoubleBuffer
 16  *
 17  * 這些緩衝區的管理方式幾乎一致,經過allocate()獲取緩衝區。
 18  *
 19  * 2、緩衝區存取數據的兩個核心的方法:
 20  * put() 存入數據到緩衝區
 21  * get() 獲取緩衝區的數據
 22  *
 23  * 3、緩衝區中的四個核心屬性:
 24  * capacity:容量,表示緩衝區中最大的存儲數據的容量,一旦聲明不能改變
 25  * limit:界限,表示緩衝區中能夠操做數據的大小。(limit後數據不能進行讀寫)
 26  * position:位置,表示緩衝區中正在操做數據的位置。
 27  *      0 <= mark <=   position <= limit <= capacity
 28  * mark:標記,表示記錄當前position的位置,經過reset()恢復到mark的位置
 29  *
 30  * 4、直接緩衝區和非直接緩衝區
 31  * 非直接緩衝區:經過allocate()分配緩衝區,將緩衝區創建在JVM的內存中
 32  * 直接緩衝區:經過allocateDirect()分配直接緩衝區,將緩衝區創建在物理內存中,能夠提升效率。
 33  */
 34 public class TestBuffer {
 35 
 36     public static void main(String[] args) {
 37 
 38         String str = "abcde";
 39 
 40         //1.分配一個指定大小的緩衝區
 41         ByteBuffer buf = ByteBuffer.allocate(1024);
 42 
 43         System.out.println("-----------allocate()----------");
 44         System.out.println(buf.position());
 45         System.out.println(buf.limit());
 46         System.out.println(buf.capacity());//0 1024 1024
 47 
 48         //2.利用put()存入數據到緩衝區
 49         buf.put(str.getBytes());
 50         System.out.println("-----------put()----------");
 51         System.out.println(buf.position());
 52         System.out.println(buf.limit());
 53         System.out.println(buf.capacity()); //5 1024 1024
 54 
 55         //3.利用flip()切換成讀數據模式
 56         buf.flip();
 57         System.out.println("-----------flip()----------");
 58         System.out.println(buf.position());
 59         System.out.println(buf.limit());
 60         System.out.println(buf.capacity()); //0 5 1024
 61 
 62         //4.利用get()讀取緩衝區中的數據
 63         byte[] dst = new byte[buf.limit()];
 64         buf.get(dst);
 65         System.out.println(new String(dst, 0, dst.length));
 66         System.out.println("-----------get()----------");
 67         System.out.println(buf.position());
 68         System.out.println(buf.limit());
 69         System.out.println(buf.capacity()); //5 5 1024
 70 
 71         //5.rewind()可重複讀數據
 72         buf.rewind();
 73         System.out.println("-----------rewind()----------");
 74         System.out.println(buf.position());
 75         System.out.println(buf.limit());
 76         System.out.println(buf.capacity()); //0 5 1024
 77 
 78         //6.清空緩衝區,可是緩衝區裏面的數據依然存在,數據存在被遺忘狀態
 79         buf.clear();
 80         System.out.println("-----------clear()----------");
 81         System.out.println(buf.position());
 82         System.out.println(buf.limit());
 83         System.out.println(buf.capacity()); //0 1024 1024
 84 
 85         System.out.println((char)buf.get());//a
 86 
 87 
 88         //--------------------------------------------------------------
 89         String str2 = "abcde";
 90         ByteBuffer buf2 = ByteBuffer.allocate(1024);
 91         buf2.put(str2.getBytes());
 92 
 93         buf2.flip();
 94 
 95         byte[] dst2 = new byte[buf.limit()];
 96         buf2.get(dst2, 0, 2);
 97 
 98         System.out.println(new String(dst2, 0, 2));
 99         System.out.println(buf2.position());//2
100 
101         //mark() 標記
102         buf2.mark();
103 
104         buf2.get(dst2, 2, 2);
105         System.out.println(new String(dst2, 2, 2));
106         System.out.println(buf2.position());//4
107 
108         //reset()恢復到mark的位置
109         buf2.reset();
110         System.out.println(buf2.position());//2
111 
112         //--------------------------------------------------------------
113         //分配直接緩衝區
114         ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
115         System.out.println(buffer.isDirect()); //判斷是不是直接緩衝區
116     }
117 }
相關文章
相關標籤/搜索