場景:文件讀出數(shù)據(jù),傳到另一臺服務(wù)器上
偽代碼? File.read(file, buf, len);? ? Socket.send(socket, buf, len);? ?4次數(shù)據(jù)拷貝,用戶態(tài)和內(nèi)核態(tài)區(qū)別

1、read()一次上下文切換(用戶態(tài)->內(nèi)核態(tài)),底層用DMA(direct memory access)讀磁盤文件,存儲到內(nèi)核地址空間的讀取緩存區(qū)
2、程序無法訪問內(nèi)核地址空間數(shù)據(jù),從讀取拷貝到用戶緩沖區(qū)。第二次切換(內(nèi)核態(tài)->用戶態(tài)),可修改數(shù)據(jù)。
3、終目通過Socket傳到另一個服務(wù),send()第三次切換(用戶態(tài)->內(nèi)核態(tài)),緩沖區(qū)與目標(biāo)套接字相關(guān)聯(lián),與讀取緩沖區(qū)無關(guān)。
4、send()返回,第四次切換,DMA把數(shù)據(jù)從目標(biāo)套接字相關(guān)的緩存區(qū)傳到協(xié)議引擎進(jìn)行發(fā)送。
1和4是由DMA負(fù)責(zé),不會消耗CPU,只有過程2和3的拷貝需要CPU參與
好幾次拷貝多余,影響性能
一、零拷貝優(yōu)化
不需要操作內(nèi)容,2和3多余,直接把內(nèi)核態(tài)讀取緩存沖區(qū)數(shù)據(jù)直接拷貝到套接字相關(guān)的緩存區(qū)

切換四次減到兩次,拷貝四次減到三(其中DMA copy 2次,CPU copy 1次)
FileChannel的transferTo() 可以實(shí)現(xiàn),數(shù)據(jù)從文件通道傳輸?shù)浇o定可寫字節(jié)通道, file.read()和socket.send()替換為transferTo()調(diào)用"
public void transferTo(long position, long count, WritableByteChannel target);
但不是零拷貝(一次cpu)
二、零拷貝實(shí)現(xiàn)

1、transferTo() 用 DMA 將文件拷貝到內(nèi)核讀取緩沖區(qū)。
2、避免內(nèi)容整體拷貝,只位置和長度追加到套接字緩沖區(qū),DMA 引擎直接把數(shù)據(jù)從內(nèi)核緩沖區(qū)傳到協(xié)議引擎,消除最后一次 CPU拷貝
ps:面試從用戶態(tài)談到內(nèi)核態(tài),socket談到FileChannel,從NIO談到Netty,從直接內(nèi)存到CompositeBy