Netty 新手关于 WARNING: Failed to release a message: PooledUnsafeDirectByteBuf(freed) 的问题

Netty neophyte question on WARNING: Failed to release a message: PooledUnsafeDirectByteBuf(freed)

我正在通过 Netty In Action 书和代码示例学习 Netty,用于 https://github.com/normanmaurer/netty-in-action/tree/2.0-SNAPSHOT/chapter2

中的第 2 章示例

我添加了另一个 AnotherEchoServerHandler extends ChannelInboundHandlerAdapter,在 AnotherEchoServerHandler.channelRead 方法中,我将其更新为:

public void channelRead(ChannelHandlerContext ctx, Object msg) {
    ByteBuf in = (ByteBuf) msg;
    System.out.println(
            "Log from AnotherEchoServerHandler that Server received: " + in.toString(CharsetUtil.UTF_8));
    ctx.fireChannelRead(msg);
    ctx.write(in);
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx)
        throws Exception {
    ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
            .addListener(ChannelFutureListener.CLOSE);
}

EchoServer 中,我添加了新的 ChannelHandler 作为 :

 ch.pipeline().addLast(new AnotherEchoServerHandler()).addLast(serverHandler);

连同另一个 EchoServerHandler,我现在有两个 ChannelHandler,我想从每个 ChannelHandler 打印一条消息,并从每个 ChannelHandler 向客户端写回一条消息ChannelHandler.

运行 上面这个改动的书例:

在服务器端,它记录:

[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ echo-server ---
nia.chapter2.echoserver.EchoServer started and listening for connections on /0:0:0:0:0:0:0:0:8888
Log from AnotherEchoServerHandler that Server received: Netty rocks!
Server received: Netty rocks!

在客户端,它记录:

Client received: Netty rocks!Netty rocks!

如你所见,我在双方都得到了预期的信息,但我也在服务器端看到了一个警告:

Mar 30, 2021 6:25:29 PM io.netty.util.ReferenceCountUtil safeRelease
WARNING: Failed to release a message: PooledUnsafeDirectByteBuf(freed)
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release0(AbstractReferenceCountedByteBuf.java:101)
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:89)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:84)
    at io.netty.util.ReferenceCountUtil.safeRelease(ReferenceCountUtil.java:109)
    at io.netty.channel.ChannelOutboundBuffer.remove(ChannelOutboundBuffer.java:256)
    at io.netty.channel.ChannelOutboundBuffer.removeBytes(ChannelOutboundBuffer.java:337)
    at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:448)
    at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:856)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:362)
    at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:823)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1296)
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)
    at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:802)
    at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814)
    at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794)
    at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:831)
    at nia.chapter2.echoserver.AnotherEchoServerHandler.channelReadComplete(AnotherEchoServerHandler.java:30)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:398)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:380)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelReadComplete(AbstractChannelHandlerContext.java:373)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelReadComplete(DefaultChannelPipeline.java:1339)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:398)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:380)
    at io.netty.channel.DefaultChannelPipeline.fireChannelReadComplete(DefaultChannelPipeline.java:932)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:139)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
    at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:858)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
    at java.lang.Thread.run(Thread.java:748

这条警告消息是什么意思? 如何避免它?

Along with the other EchoServerHandler, I have two ChannelHandler now, I'd like to print a message from each ChannelHandler, and write back a message to Client from each ChannelHandler.

EchoServerHandler也会写成msg。这将导致 msgChannelOutboundBuffer 中被释放两次。

您可以在写入 AnotherEchoServerHandler

之前删除 EchoServerHandler 或调用 in.retain()