非直接緩衝區:經過 allocate() 方法分配緩衝區,將緩衝區創建在 JVM 的內存中安全
上圖讀的過程: 讀物理磁盤文件時候,先到物理內存讀到,而後拷貝到jvm內存中。 程序去jvm讀取。 從物理空間拷貝到jvm內存空間,效率慢。app
寫的過程: 先寫到jvm內存,jvm拷貝到物理內存,而後再到物理磁盤。jvm
非直接緩衝區 直接存放在 jvm緩衝區 須要來回copy性能
非直接緩衝區 存放在物理內存 不須要copyspa
存放在物理內存比jvm緩衝區效率高 操作系統
直接緩衝區:經過 allocateDirect() 方法分配直接緩衝區,將緩衝區創建在物理內存中。能夠提升效率code
非直接緩衝區:blog
應用程序 不走jvm內存和物理內存。 走的是物理內存映射文件。內存條ip
寫: 直接寫到物理內存映射文件,到物理磁盤內存
讀: 物理磁盤文件讀到物理內存映射文件,而後讀取之
直接緩衝區 佔內存 不安全 可是效率高
字節緩衝區要麼是直接的,要麼是非直接的。若是爲直接字節緩衝區,則 Java 虛擬機會盡最大努力直接在此緩衝區上執行本機 I/O 操做。也就是說,在每次調用基礎操做系統的一個本機 I/O 操做以前(或以後),虛擬機都會盡可能避免將緩衝區的內容複製到中間緩衝區中(或從中間緩衝區中複製內容)。
直接字節緩衝區能夠經過調用此類的 allocateDirect() 工廠方法來建立。此方法返回的緩衝區進行分配和取消分配所需成本一般高於非直接緩衝區。直接緩衝區的內容能夠駐留在常規的垃圾回收堆以外,所以,它們對應用程序的內存需求量形成的影響可能並不明顯。因此,建議將直接緩衝區主要分配給那些易受基礎系統的本機 I/O 操做影響的大型、持久的緩衝區。通常狀況下,最好僅在直接緩衝區能在程序性能方面帶來明顯好處時分配它們。
直接字節緩衝區還能夠經過 FileChannel 的 map() 方法 將文件區域直接映射到內存中來建立。該方法返回MappedByteBuffer 。 Java 平臺的實現有助於經過 JNI 從本機代碼建立直接字節緩衝區。若是以上這些緩衝區中的某個緩衝區實例指的是不可訪問的內存區域,則試圖訪問該區域不會更改該緩衝區的內容,而且將會在訪問期間或稍後的某個時間致使拋出不肯定的異常。
字節緩衝區是直接緩衝區仍是非直接緩衝區可經過調用其 isDirect() 方法來肯定。提供此方法是爲了可以在性能關鍵型代碼中執行顯式緩衝區管理。
IO緩衝區 非直接緩衝區
// 使用直接緩衝區完成文件的複製(內存映射文件) static public void test2() throws IOException { long start = System.currentTimeMillis(); FileChannel inChannel = FileChannel.open(Paths.get("f://1.mp4"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("f://2.mp4"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); // 內存映射文件 MappedByteBuffer inMappedByteBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size()); MappedByteBuffer outMappedByteBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size()); // 直接對緩衝區進行數據的讀寫操做 byte[] dsf = new byte[inMappedByteBuf.limit()]; inMappedByteBuf.get(dsf); outMappedByteBuffer.put(dsf); inChannel.close(); outChannel.close(); long end = System.currentTimeMillis(); System.out.println(end - start); } // 1.利用通道完成文件的複製(非直接緩衝區) static public void test1() throws IOException { // 4400 long start = System.currentTimeMillis(); FileInputStream fis = new FileInputStream("f://1.mp4"); FileOutputStream fos = new FileOutputStream("f://2.mp4"); // ①獲取通道 FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel(); // ②分配指定大小的緩衝區 ByteBuffer buf = ByteBuffer.allocate(1024); while (inChannel.read(buf) != -1) { buf.flip();// 切換爲讀取數據 // ③將緩衝區中的數據寫入通道中 outChannel.write(buf); buf.clear(); } outChannel.close(); inChannel.close(); fos.close(); fis.close(); long end = System.currentTimeMillis(); System.out.println(end - start); }