預(yù)備知識關(guān)于I/O內(nèi)存映射。 設(shè)備通過控制總線,數(shù)據(jù)總線,狀態(tài)總線與CPU相連??刂瓶倲?shù)傳送控制信號。在傳統(tǒng)的操作中,都是通過讀寫設(shè)備寄存器的值來實現(xiàn)。但是這樣耗費了CPU時鐘。而且每取一次值都要讀取設(shè)備寄存器,造成了效率的低下。在現(xiàn)代操作系統(tǒng)中。引用了I/O內(nèi)存映射。即把寄存器的值映身到主存。對設(shè)備寄存器的操作,轉(zhuǎn)換為對主存的操作,這樣極大的提高了效率。 關(guān)于DMA傳統(tǒng)的處理方法為:當(dāng)設(shè)備接收到數(shù)據(jù),向CPU報告中斷。CPU處理中斷,CPU把數(shù)據(jù)從設(shè)備的寄存器數(shù)據(jù)讀到內(nèi)存。 在現(xiàn)代操作系統(tǒng)中引入的DMA設(shè)備,設(shè)備接收到數(shù)據(jù)時,把數(shù)據(jù)放至DMA內(nèi)存,再向CPU產(chǎn)生中斷。這樣節(jié)省了大量的CPU時間 什么是零拷貝? 零拷貝描述的是CPU不執(zhí)行拷貝數(shù)據(jù)從一個存儲區(qū)域到另一個存儲區(qū)域的任務(wù),這通常用于通過網(wǎng)絡(luò)傳輸一個文件時以減少CPU周期和內(nèi)存帶寬。 避免數(shù)據(jù)拷貝
零拷貝給我們帶來的好處
零拷貝完全依賴于操作系統(tǒng)。操作系統(tǒng)支持 通過sendfile實現(xiàn)的零拷貝I/Osendfile(socket, file, len);//file可以是文件句柄,也可以是socket句柄 把文件數(shù)據(jù)通過網(wǎng)絡(luò)發(fā)送出去,減少了上下文的切換,內(nèi)核的緩存數(shù)據(jù)到直接網(wǎng)卡數(shù)據(jù)也不用CPU去復(fù)制,由DMA完成
通過sendfile實現(xiàn)的零拷貝I/O只使用了2次用戶空間與內(nèi)核空間的上下文切換,以及3次數(shù)據(jù)的拷貝。實現(xiàn)了把數(shù)據(jù)從文件發(fā)送到網(wǎng)卡。 傳統(tǒng)的IO流程實現(xiàn)文件數(shù)據(jù)發(fā)送read(file, tmp_buf, len);write(socket, tmp_buf, len);
第4步DMP把socket緩存數(shù)據(jù)復(fù)制到網(wǎng)卡緩存上 經(jīng)過4次上下文切換,4次數(shù)據(jù)拷貝,在數(shù)據(jù)量比較大時,性能比sendfile方式低下 通過mmap實現(xiàn)的零拷貝I/Ommap(內(nèi)存映射)是一個比sendfile昂貴但優(yōu)于傳統(tǒng)I/O的方法。 MappedByteBuffer 在調(diào)用FileChannel.map()時使用。 與DirectByteBuffer類似,這也是JVM堆外部的情況。 它基本上作為OS mmap()系統(tǒng)調(diào)用的包裝函數(shù),以便代碼直接操作映射的物理內(nèi)存數(shù)據(jù)。 HeapByteBuffer 在調(diào)用ByteBuffer.allocate()時使用。 它被稱為堆,因為它保存在JVM的堆空間中,因此你可以獲得所有優(yōu)勢,如GC支持和緩存優(yōu)化。 但是,它不是頁面對齊的,這意味著如果你需要通過JNI與本地代碼交互時,比如寫入網(wǎng)卡,寫入磁盤,JVM將不得不復(fù)制到系統(tǒng)的頁緩沖區(qū)空間。 DirectByteBuffer 在調(diào)用ByteBuffer.allocateDirect()時使用。 JVM在堆空間之外分配內(nèi)存空間。 因為它不是由JVM管理的,所以你的內(nèi)存空間是頁面對齊的,不受GC影響,這使得它成為處理本地代碼的完美選擇。 然而,你要C程序員一樣,自己管理這個內(nèi)存,必須自己分配和釋放內(nèi)存來防止內(nèi)存泄漏。 splice 在兩個文件描述符之間傳輸數(shù)據(jù),不用拷貝。但輸入和輸出文件描述符必須有一個是pipe。也就是說如果你需要從一個socket 傳輸數(shù)據(jù)到另外一個socket,是需要使用 pipe來做為中介的 splice (socket1_fd, pipe_fd) splice (pipl_fd, socket2_fd) |
|
|