netty中的零拷貝

Netty的零拷貝體如今三個方面:java

  1. buffer層面

對於ByteBuf,Netty提供了多種實現:
a. Heap ByteBuf:直接在堆內存分配
b. Direct ByteBuf:直接在內存區域分配而不是堆內存(零拷貝)
c. CompositeByteBuf:組合Buffer(零拷貝)數組

1.1 ByteBuffer:Netty的接收和發送ByteBuffer採用DIRECT BUFFERS,使用堆外直接內存進行Socket讀寫,不須要進行字節緩衝區的二次拷貝。若是使用傳統的堆內存(HEAP BUFFERS)進行Socket讀寫,JVM會將堆內存Buffer拷貝一份到直接內存中,而後才寫入Socket中。相比於堆外直接內存,消息在發送過程當中多了一次緩衝區的內存拷貝。
DIRECT BUFFERS直接在內存區域分配空間,而不是在堆內存中分配。若是使用傳統的堆內存分配,當咱們須要將數據經過socket發送的時候,就須要從堆內存拷貝到直接內存,而後再由直接內存拷貝到網卡接口層。
Netty提供的直接Buffer,直接將數據分配到內存空間,從而避免了數據的拷貝,實現了零拷貝網絡

1.2 Netty提供了組合Buffer對象,即Composite Buffers,能夠聚合多個ByteBuffer對象,用戶能夠像操做一個Buffer那樣方便的對組合Buffer進行操做,避免了傳統經過內存拷貝的方式將幾個小Buffer合併成一個大的Buffer。

傳統的ByteBuffer,若是須要將兩個ByteBuffer中的數據組合到一塊兒,咱們須要首先建立一個size=size1+size2大小的新的數組,而後將兩個數組中的數據拷貝到新的數組中。可是使用Netty提供的組合ByteBuf,就能夠避免這樣的操做,由於CompositeByteBuf並無真正將多個Buffer組合起來,而是保存了它們的引用,從而避免了數據的拷貝,實現了零拷貝socket

2.操做系統層面
Netty的文件傳輸採用了transferTo方法,它能夠直接將文件緩衝區的數據發送到目標Channel,避免了傳統經過循環write方式致使的內存拷貝問題
傳統意義的網絡傳輸主要包括:
image.png
這種方式須要四次數據拷貝和四次上下文切換:
a. 數據從磁盤讀取到內核的read buffer
b. 數據從內核緩衝區拷貝到用戶緩衝區
c. 數據從用戶緩衝區拷貝到內核的socket buffer
d. 數據從內核的socket buffer拷貝到網卡接口的緩衝區

明顯上面的第二步和第三步是沒有必要的,經過java的FileChannel.transferTo方法,能夠避免上面兩次多餘的拷貝(固然這須要底層操做系統支持).netty中採用nio的零拷貝後:
image.pngspa

a. 調用transferTo,數據從文件由DMA引擎拷貝到內核read buffer
b. 接着DMA從內核read buffer將數據拷貝到網卡接口buffer操作系統

相關文章
相關標籤/搜索