轉自:https://sanwen8.cn/p/1bfoy1F.html
Netty爲了提升報文的讀寫性能,默認會採用“零拷貝”模式,即消息讀取時使用非堆的DirectBuffer來減少ByteBuffer的內存拷貝,如下圖所示:
如果需要修改接收Buffer的類型,例如從DirectByteBuf修改爲HeapByteBuf,首先需要在初始化Channel的時候對接收緩衝區進行設置,客戶端代碼示例如下:
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)
如果是服務端,則需要在鏈路創建之後,初始化時對Channel的SocketChannelConfig的Allocator屬性進行設置,代碼如下:
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.config().setAllocator(UnpooledByteBufAllocator.DEFAULT);
無論是通過ChannelOption.RCVBUF_ALLOCATOR還是Allocator,都只能設置Allocator的類型,無法直接設置ByteBufAllocator分配的ByteBuf類型。下面我們接着分析消息讀取時的ByteBuf分配機制。消息讀取時,調用的是NioByteUnsafe的read方法,代碼如下:
首先從SocketChannelConfig中獲取ByteBufAllocator,在這裏就是UnpooledByteBufAllocator,然後調用它的ioBuffer方法分配內存,它的具體實現如下:
@Override
public ByteBuf ioBuffer() {
if (PlatformDependent.hasUnsafe()) {
return directBuffer(0);
}
return heapBuffer(0);
}
如果非Unsafe模式,則會使用堆內存heapBuffer,接着看hasUnsafe方法實現,它最終會調用如下方法:
設置io.netty.noUnsafe屬性爲true,則默認會使用Heap堆內存創建ByteBuf,下面我們在啓動時設置-Dio.netty.noUnsafe爲true進行測試
設置完成之後,使用Echo程序進行測試,測試結果如下:
總結
利用ch.config().setAllocator或Bootstrap.option(ChannelOption.ALLOCATOR, ByteBufAllocator),結合-Dio.netty.noUnsafe,可以靈活的在如下四種ByteBuf之間進行切換:
-
UnpooledHeapByteBuf
-
PooledHeapByteBuf
-
UnpooledDirectByteBuf
-
PooledDirectByteBuf