1. 程式人生 > >netty那些bytebuf踩過的坑

netty那些bytebuf踩過的坑

程式超過256個位元組以後用抓包工具抓包顯示訊息已經發送給服務端並且服務端也回發了ack表示已經收到了,但是在read方法裡並沒有收到訊息。
幾經輾轉發現問題出現在編解碼器上,自己定義的解碼器是這樣的:

ByteBuf heapBuffer = ctx.alloc().heapBuffer();
        in.readBytes(heapBuffer, in.resetReaderIndex().readableBytes());
        out.add(heapBuffer);

問題就出在第二句上了,它的方法描述如下:
這裡寫圖片描述
這裡使用readbytes方法拷貝bytebuf物件。但是bytebuf在沒有分配大小時寫大小預設是256。當寫入的時候發現長度不夠,於是就丟擲了異常。在伺服器上異常不知道為什麼沒有打印出來,所以找了很久都沒找到原因。
但是每隔一段時間會報:

ERROR|io.netty.util.ResourceLeakDetector] - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 
Created at:
    io.netty.buffer.PooledByteBufAllocator.newHeapBuffer(PooledByteBufAllocator.java
:314) io.netty.buffer.AbstractByteBufAllocator.heapBuffer(AbstractByteBufAllocator.java:166) io.netty.buffer.AbstractByteBufAllocator.heapBuffer(AbstractByteBufAllocator.java:152) com.montnets.po.conf.CustomDecoder.decode(CustomDecoder.java:42) io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java
:489) io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) java.lang.Thread.run(Thread.java:748)

提示bytebuf在垃圾回收之前沒有被釋放!在程式碼裡每次用完bytebuf都有釋放的,所以一時也不知道什麼原因。
但因為上面的問題邏輯大概通透了。
因為呼叫readBytes()方法的時候異常,所以並沒有進入到read方法中,我的bytebuf都是在read中釋放的,所以在解碼器中建立的這個bytebuf自然是沒有被釋放的了!
最後看懂的小夥伴應該已經知道解決方法了,就是在呼叫ByteBuf heapBuffer = ctx.alloc().heapBuffer(); 的時候給它分配大小。ByteBuf heapBuffer = ctx.alloc().heapBuffer(readableBytes);