這裏只是感性地認識Linux零拷貝,不涉及具體細節。網絡
1.Linux傳統的數據拷貝socket
用戶進程是不能直接訪問文件系統的,要先切換到內核態,發起系統調用,DMA把磁盤中的數據寫入內核空間,內核再把數據拷貝到用戶空間,用戶進程才能操做這些數據。spa
如上把磁盤上的文件發送到網絡,將會發生4次狀態切換,2次cpu拷貝。3d
2. 2.4版本前blog
(1)基於mmap(可修改數據)+write進程
將會有4次狀態切換,1次cpu拷貝。ip
由於內存映射老是要對齊頁邊界(最小單位爲4kb),因此可能會形成碎片空間的浪費,一個5kb的文件要映射佔用8kb的空間,浪費了3kb。內存
(2)基於sendFile(不可修改數據,jdk nio中transferFrom,transferTo,數據從一個channel直接傳輸到另外一個channel即是依賴於此)it
將會有2次狀態切換,1次cpu拷貝。pip
3. 2.4版本後,基於mmap(用於修改數據,後續版本中若是共享區爲多個進程共有,將會寫時複製,拷貝到用戶空間)+gather
Linux 2.4 版本的內核對 sendfile 系統調用進行修改,爲 DMA (要硬件支持)拷貝引入了 gather 操做。它將內核空間(kernel space)的讀緩衝區(read buffer)中對應的數據描述信息(內存地址、地址偏移量)記錄到相應的網絡緩衝區( socket buffer)中,由 DMA 根據內存地址、地址偏移量將數據批量地從讀緩衝區(read buffer)拷貝到網卡設備中。
將有2次狀態切換,0次cpu拷貝。
4. 2.6.17版本後,splice(用戶進程不能修改數據)
splice 系統調用(不需硬件支持)能夠在內核空間的讀緩衝區(read buffer)和網絡緩衝區(socket buffer)之間創建管道(pipeline),從而避免了二者之間的 CPU 拷貝操做。
將有2次狀態切換,0次cpu拷貝。