Netty读取消息出现IllegalReferenceCountException refCnt:0异常原因问询
问题原因
触发IllegalReferenceCountException: refCnt:0的核心原因是操作顺序与Netty的引用计数释放规则冲突:
- Netty对入站的ByteBuf类型消息,默认会在消息走完整个ChannelPipeline后,由末端的TailHandler自动执行释放操作,将引用计数减为0。
- 你的代码在
channelRead方法中优先执行了super.channelRead(ctx, msg),如果父类DriverResponseHandler继承了标准的ChannelInboundHandlerAdapter,该调用会将消息向后传递给Pipeline的下一个Handler,直到走完流程被自动释放。后续你再调用received.writeBytes((ByteBuf) msg)访问已经被释放的ByteBuf,就会触发引用计数异常。
除此之外你的代码还存在内存泄漏隐患:在channelReadComplete中为received重新分配新的ByteBuf时,旧的received没有调用release()释放,会导致堆外内存无法被回收。
修复方案
调整操作顺序,先处理入站ByteBuf再向后传递消息,同时补充内存释放逻辑:
public class ResponseHandler extends DriverResponseHandler { private ByteBuf received; @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { super.handlerAdded(ctx); received = ctx.alloc().buffer(32); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { try { // 先操作入站ByteBuf received.writeBytes((ByteBuf) msg); } finally { // 操作完成后再向后传递消息,由后续流程负责释放msg // 如果你不需要将消息向后传递,可以直接调用ReferenceCountUtil.release(msg),无需执行super调用 super.channelRead(ctx, msg); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { super.channelReadComplete(ctx); if (received.writerIndex() == received.capacity() || received.readerIndex() == received.capacity()) { // 释放旧的ByteBuf避免内存泄漏 received.release(); received = ctx.alloc().buffer(32); } processResponse(received); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { super.handlerRemoved(ctx); // Handler移除时释放持有的ByteBuf,避免内存泄漏 if (received != null && received.refCnt() > 0) { received.release(); } } }
内容的提问来源于stack exchange,提问作者WinterMute
相关产品推荐
相关产品推荐

