淺析Java?NIO?直接緩沖區(qū)和非直接緩沖區(qū)
定義
以上是書《深入理解java虛擬機》對直接內(nèi)存的描述。直接緩沖區(qū)用的就是直接內(nèi)存。
- java nio字節(jié)緩沖區(qū)要么是直接的,要么是非直接的。如果為直接字節(jié)緩沖區(qū),則java虛擬機會盡最大努力直接在此緩沖區(qū)上執(zhí)行本機的IO操作,也就是說,在每次調(diào)用基礎(chǔ)操作系統(tǒng)的一個本機IO操作前后,虛擬機都會盡量避免將內(nèi)核緩沖區(qū)內(nèi)容復(fù)制到用戶進程緩沖區(qū)中,或者反過來,盡量避免從用戶進程緩沖區(qū)復(fù)制到內(nèi)核緩沖區(qū)中。
- 直接緩沖區(qū)可以通過調(diào)用該緩沖區(qū)類的allocateDirect(int capacity) 方法創(chuàng)建,此方法返回的緩沖區(qū)進行分配和取消分配所需的成本要高于非直接緩沖區(qū)。直接緩沖區(qū)的內(nèi)容駐留在垃圾回收堆之外,因此他們對應(yīng)用程序內(nèi)存(JVM內(nèi)存)需求不大。所以建議直接緩沖區(qū)要分配給那些大型,持久(就是緩沖區(qū)的數(shù)據(jù)會被重復(fù)利用)的緩沖區(qū),一般情況下,最好僅在直接緩沖區(qū)能在程序性能帶來非常明顯的好處時才分配它們。
- 直接緩沖區(qū)還可以通過FileCHannel的map()方法將文件區(qū)域映射到內(nèi)存中來創(chuàng)建,該方法返回MappedByteBuffer。java平臺的實現(xiàn)有助于通過JNI本地代碼創(chuàng)建直接字節(jié)緩沖區(qū),如果以上這些緩沖區(qū)中某個緩沖區(qū)實例指向的是不可訪問的內(nèi)存區(qū)域,則試圖方法該區(qū)域不會更改緩沖區(qū)的內(nèi)容,并且會在訪問期間或者稍后的某個時間導(dǎo)致報出不確定性異常。
- 字節(jié)緩沖區(qū)是直接緩沖區(qū)還是非直接緩沖區(qū)可以通過調(diào)用其isDIrect()方法來判斷。
基于NIO的本地IO直接內(nèi)存使用:
傳統(tǒng)IO對文件數(shù)據(jù)進行讀寫的流程:
流程說明(以上是應(yīng)用程序完成一次文件拷貝的流程):
- 應(yīng)用進程發(fā)起一個讀請求系統(tǒng)調(diào)用,然后進程切換到內(nèi)核態(tài)。
- DMA把磁盤數(shù)據(jù)復(fù)制到內(nèi)核緩沖區(qū)中。
- 內(nèi)核把緩沖區(qū)數(shù)據(jù)復(fù)制到用戶緩沖區(qū)中。
- 進程切換到用戶態(tài)。
- 應(yīng)用進程發(fā)起一個寫請求系統(tǒng)調(diào)用,然后進程切換到內(nèi)核態(tài)。
- 內(nèi)核把用戶緩沖區(qū)數(shù)據(jù)復(fù)制到內(nèi)核緩沖區(qū)。
- DMA把內(nèi)核緩沖區(qū)數(shù)據(jù)復(fù)制到磁盤上。
- 返回。
以上流程一共進行了四次上下文切換,四次數(shù)據(jù)拷貝。
使用mmap實現(xiàn)對傳統(tǒng)文件IO優(yōu)化。
mmap:通過把內(nèi)核緩沖區(qū)和用戶緩沖區(qū)映射在物理內(nèi)存上映射為同一地址空間。這樣就不用對數(shù)據(jù)進行復(fù)制了。
這個是傳統(tǒng)的:
使用mmap后的IO大致流程:
數(shù)據(jù)拷貝次數(shù)從4次縮短到了兩次。
相關(guān)API demo以及比較:詳細api解釋可以查看Java NIO學(xué)習(xí)篇之通道FileChannel詳解
//使用直接緩沖區(qū)API進行一個700多M的文件進行拷貝 public static void testDirect(){ try { long start = System.currentTimeMillis(); FileChannel srcFileChannel = FileChannel.open(Paths.get("C:\\Users\\Yehaocong\\Desktop\\test\\95462017-1-64.flv"), StandardOpenOption.READ); FileChannel destFileChannel = FileChannel.open(Paths.get("C:\\Users\\Yehaocong\\Desktop\\test\\95462017-1-64-cp1.flv"),StandardOpenOption.CREATE, StandardOpenOption.WRITE,StandardOpenOption.READ); MappedByteBuffer srcByteBuffer = srcFileChannel.map(FileChannel.MapMode.READ_ONLY,0,srcFileChannel.size()); MappedByteBuffer descByteBuffer = destFileChannel.map(FileChannel.MapMode.READ_WRITE,0,srcFileChannel.size()); descByteBuffer.put(srcByteBuffer); srcFileChannel.close(); destFileChannel.close(); System.out.println("直接緩沖區(qū)耗時:" + (System.currentTimeMillis()-start)); } catch (IOException e) { e.printStackTrace(); } } public static void testSimpleIO(){ try { long start = System.currentTimeMillis(); FileChannel srcFileChannel = FileChannel.open(Paths.get("C:\\Users\\Yehaocong\\Desktop\\test\\95462017-1-64.flv"), StandardOpenOption.READ); FileChannel destFileChannel = FileChannel.open(Paths.get("C:\\Users\\Yehaocong\\Desktop\\test\\95462017-1-64-cp.flv"),StandardOpenOption.CREATE, StandardOpenOption.WRITE,StandardOpenOption.READ); ByteBuffer byteBuffer = ByteBuffer.allocate((int) srcFileChannel.size()); while (srcFileChannel.read(byteBuffer)!=-1){ byteBuffer.flip(); destFileChannel.write(byteBuffer); byteBuffer.clear(); } srcFileChannel.close(); destFileChannel.close(); System.out.println("非緩沖區(qū)耗時:" + (System.currentTimeMillis()-start)); } catch (IOException e) { e.printStackTrace(); } }
執(zhí)行結(jié)果:
?
到此這篇關(guān)于淺析Java NIO 直接緩沖區(qū)和非直接緩沖區(qū)的文章就介紹到這了,更多相關(guān)Java NIO 直接緩沖區(qū)和非直接緩沖區(qū)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyEclipse設(shè)置Console輸出到文件的實現(xiàn)方法
下面小編就為大家?guī)硪黄狹yEclipse設(shè)置Console輸出到文件的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07Java Scala實現(xiàn)數(shù)據(jù)庫增刪查改操作詳解
這篇文章主要介紹了Java Scala實現(xiàn)數(shù)據(jù)庫增刪查改操作,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-04-049個小技巧讓你的Java if else看起來更優(yōu)雅
這篇文章主要給大家介紹了9個小技巧,通過這幾個小技巧可以讓你的Java if else看起來更優(yōu)雅,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11簡單了解java中靜態(tài)初始化塊的執(zhí)行順序
這篇文章主要介紹了簡單了解java中靜態(tài)初始化塊的執(zhí)行順序,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10如何通過自定義spring?invalidator注解校驗數(shù)據(jù)合法性
這篇文章主要介紹了如何通過自定義spring?invalidator注解校驗數(shù)據(jù)合法性,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07Mybatis-Plus3.2.0 MetaObjectHandler 無法進行公共字段全局填充
這篇文章主要介紹了Mybatis-Plus3.2.0 MetaObjectHandler 無法進行公共字段全局填充,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11