在netty4中,对象的生命周期由引用计数器控制,ByteBuf就是如此,每个对象的初始化引用计数为1,调用一次release方法,引用计数器会减1,当尝试访问计数器为0的,对象时,会抛出IllegalReferenceCountException,正如ensureAccessible的实现,更加详细的解释可以参考官方文档
AbstractByteBuf.java
protected final void ensureAccessible() {
if (refCnt() == 0) {
throw new IllegalReferenceCountException(0);
}
}
注意TZ的TimeHandler类中的 super.channelRead(ctx, msg);这行代码。追踪调用路径,
private void invokeChannelRead(Object msg) {
try {
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
}
最终调用的代码是:ReferenceCountUtil.release(msg)
public static boolean release(Object msg) {
if (msg instanceof ReferenceCounted) {
return ((ReferenceCounted) msg).release();
}
return false;
}
也就是每次super.channelRead(ctx, msg);后,ByteBuf就会调用release()方法,计数器减一,然后在 buf.readBytes(butfs);这行代码就会校验ensureAccessible(),计数器为0,netty认为ByteBuf对象已经释放,就抛出异常。
解决方案:
去掉TimeHandler中这行代码 super.channelRead(ctx, msg);
ByteBuf对象谁处理谁释放。
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…