NIO零拷貝
普通IO操作流程
image.png
- 用戶程序向內(nèi)核程序發(fā)起讀請(qǐng)求
- cpu從用戶模式切換到內(nèi)核模式希坚,內(nèi)核模式向磁盤發(fā)出讀取數(shù)據(jù)的請(qǐng)求
- 磁盤將數(shù)據(jù)讀取到內(nèi)核空間的緩沖區(qū)
- 內(nèi)核將數(shù)據(jù)從緩沖區(qū)拷貝到用戶空間的緩沖區(qū)
- 執(zhí)行邏輯代碼
- 執(zhí)行write方法柴钻,將數(shù)據(jù)寫到網(wǎng)絡(luò)的另一端。
- 將數(shù)據(jù)從用戶空間拷貝回內(nèi)核空間
- 將數(shù)據(jù)真正的寫到磁盤或者socket中
這種方式會(huì)導(dǎo)致系統(tǒng)遇到瓶頸货葬,為傳統(tǒng)IO操作
零拷貝
零拷貝依賴于操作系統(tǒng)采幌,操作系統(tǒng)實(shí)現(xiàn)了,則實(shí)現(xiàn)震桶,沒有實(shí)現(xiàn)則沒有實(shí)現(xiàn)休傍,跟java程序無關(guān)。
image.png
- 從圖中可以看出對(duì)用戶空間的數(shù)據(jù)拷貝已經(jīng)沒了蹲姐。
- 內(nèi)核空間收到sendfile()申請(qǐng)
- 內(nèi)核空間向磁盤發(fā)送數(shù)據(jù)讀取請(qǐng)求
- 磁盤將數(shù)據(jù)讀取到內(nèi)核空間緩沖區(qū)
- 將數(shù)據(jù)寫入到socket緩沖區(qū)中
- 通過socket緩沖區(qū)向網(wǎng)絡(luò)客戶端發(fā)送數(shù)據(jù)
- 結(jié)果返回
- sendfile()調(diào)用返回
這種操作我們稱為零拷貝磨取,相對(duì)與上一種情況有了極大的提升。
思考:
我們能不能減少磁盤拷貝到內(nèi)核的情況柴墩,而是將磁盤數(shù)據(jù)直接拷貝到socket緩沖區(qū)中忙厌??
第二版零拷貝
image.png
這種方式實(shí)現(xiàn)了從磁盤空間直接讀入Socket緩沖區(qū)
最終版零拷貝
image.png
- 用戶程序發(fā)送sendfile()指令給內(nèi)核空間并返回到用戶空間
- 內(nèi)核空間從磁盤采用DMA copy將數(shù)據(jù)從磁盤拷貝到了內(nèi)核空間
- 將內(nèi)核緩沖區(qū)的數(shù)據(jù)的文件描述符的信息拷貝到socketbuffer江咳,而不是數(shù)據(jù)逢净。文件描述中含有數(shù)據(jù)的內(nèi)存地址等信息。
- protocol協(xié)議直接通過socketbuffer中讀取到文件描述符信息從而找到kernel buffer存儲(chǔ)數(shù)據(jù)的內(nèi)存地址以及所需讀取字符的長度歼指。并將kernel buffer中的數(shù)據(jù)發(fā)送服務(wù)端
內(nèi)存映射:
問題:上面的情況用戶無法參與到數(shù)據(jù)的讀取與寫入的過程爹土,如果用戶需要參與呢?踩身?
內(nèi)存映射文件:
通過代碼的方式將文件映射到系統(tǒng)內(nèi)核空間胀茵,這樣修改文件只需要訪問內(nèi)核空間就可以。