-
在java程序中,常用的零拷貝有mmap(內存映射)和sendFile。先看一下java傳統IO和網絡編程的一段代碼
上述代碼:
1) 首先先把Hard Driver(硬件)數據進行DMA(direct memory acces 直接內存拷貝,不使用CPU)copy 到 kernel Buffer(內核緩衝區中)
2) 接下來從kernel Buffer 通過 CPU copy 到 user Buffer。
3) 此時用戶進行一些操作後,通過 CPU copy 到 socket buffer
4) 然後再通過DMA copy 到protocol engine(協議棧)。總結一下,經行了4次拷貝,3次上下文切換。
-
所以出現mmap,即內存映射優化技術。將文件映射到內核緩存區,同時,用戶空間可以共享內核空間的數據,這樣,在進行網絡傳輸時,可以減少內核空間到用戶空間的拷貝次數。即減少了上述步驟2。總結一下,經行了3次拷貝,3次上下文切換。
-
於是又出現sendFile。Linux2.1版本提供了sendFile函數,其基本原理:數據根本不經過用戶態,直接從內核進入到socket Buffer,同時,由於和用戶態無關,就減少了一次上下文切換。即減少了上述步驟2和3。總結一下,經行了3次拷貝,2次狀態切換
-
sendFile優化,在linux的2.4版本中,做了一些修改,避免了從內核緩衝區拷貝到socketBuffer的操作,直接拷貝到協議棧,從而在減少了數據庫拷貝。但是還是有少部分數據要經過一次CPU拷貝,kernel buffer->socketBuffer,如數據長度,偏移量。X消耗低,可以忽略不記
所以總共經過2次拷貝,2次上下文切換(這就是零拷貝)
5. 我們說的零拷貝,是從操作系統角度來說的,因爲內核緩衝區之間,沒有數據是重複的(只有kernel buffer有一份數據)
6. NIO實現零拷貝調用transferto()方法
在linux下,一次調用transferto()方法可以完成傳輸
在window下,調用一次transferto()方法只能發送8M數據,就需要分段傳輸文件