Netty 中的报错信息:refCnt : 0,decrememt : 1,分析源码,从根本上解决

使用Netty框架编程,最常见的报错信息之一是:refCnt : 0,decrememt : 1,那么如何解决这个错误呢?

问题分析:当创建一个Bytebuf对象时,它的引用为1,每次调用ratain(),它的引用就会加1,每次调用一个release()就会减1;如果引用为0,再次访问这个Bytebuf对象时,就会抛出refCnt : 0,decrememt : 1 的报错信息。

第一步,查看异常信息,注意红框,这是报错的具体行数:

第二步,查看代码,发现在入口程序类中继承了SimpleChannelInboundHandler类,如下图所示:

@Service("entranceHandler")
@ChannelHandler.Sharable
public class EntranceHandler extends SimpleChannelInboundHandler{

  private static Logger log = LoggerFactory.getLogger(EntranceHandler.class);

  @Override
  protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
    log.info("....首次连接的判断....");
    ByteBuf byteBuf = (ByteBuf) msg;

    // 标记一下当前的readIndex的位置
    byteBuf.markReaderIndex();
    // 判断包头长度
    if (byteBuf.readableBytes() < ProtoInstant.FILED_LEN) {// 不够包头
      return;
    }
    // 读取字头
    int head = CharacterConvert.byteToInt(byteBuf.readByte());
    //重置读索引
    byteBuf.resetReaderIndex();
    if (head == ProtoInstant.FIELD_HEAD) {
      log.info("....节点间的/netty client的连接建立....");
      //http请求响应
      ctx.channel().pipeline().remove("httpRequestDecoder");
      ctx.channel().pipeline().remove("httpResponseEncoder");
      //websocket连接的建立
      ctx.channel().pipeline().remove("websocketConnectHandler");
      //websocket编码解码
      ctx.channel().pipeline().remove("binaryDeCoder");
      ctx.channel().pipeline().remove("binaryEncoder");
    } else {
      log.info("....websocket连接建立....");
      ctx.channel().pipeline().remove("bdeCoder");
      ctx.channel().pipeline().remove("benCoder");
    }
        ctx.fireChannelRead(byteBuf);
        //删除首次连接通道,一个连接只用到一次
        ctx.channel().pipeline().remove(this);
  }
}
 
 

原来是这里报的错,查看SimpleChannelInboundHandler源码发现,在EntranceHandler类重写channelRead0()方法时,先走的父类的channelRead方法,该方法中的finally中调用了ReferenceCountUtil类的release()方法,所以还没走到下一个handler处理器就报异常信息了。

第三,解决方法;

既然refCnt为0了,那在入口方法中出站之前调用retain0方法,这个问题就解决了;

图片

在netty里面,retain()和release()方法都是成对使用的

如果不继承SimpleChannelInboundHandler这个类,是不是就不需要再调用retain()方法呢?测试了一下,果真如此,继承ChannelInboundHandlerAdapter类,代码运行正常,没有再报refCnt : 0,decrememt : 1 异常信息。

图片

在SimpleChannelInboundHandler类中,有这样一段说明:

  1. 继承该类会调用release()方法;

  2. 如果下面还有handler处理器,请调用retain()方法;

Handler处理器,释放Bytebuf对象的三种办法:

第一种方法,继承ChannelInboundHandlerAdapter类,调用 super.channelRead(ctx, msg) 方法传递给下一个handler处理器,让下一个处理器来释放;

第二种方法,在最后一个Handler处理器手动调用release()方法释放;

第二种方法,最后一个Handler处理器继承SimpleChannelInboundHandler类,让该类帮你释放。

如果不是TailHandler(最后一个handler),最好不要继承SimpleChannelInboundHandler,不然在传递给下一个handler前还需要进行retain()处理。

你可能感兴趣的:(Netty 中的报错信息:refCnt : 0,decrememt : 1,分析源码,从根本上解决)