netty中bytebuf的复用

Reusing of bytebuf in netty

我有一个 Netty 的 http 服务。对于一组请求,在 http 正文中只有“{}”的相同回复。 我有一个想法避免为每个这样的请求等创建新的缓冲区,所以我刚刚使用:

private static final ByteBuf EMPTY_REPLY = Unpooled.copiedBuffer("{}", CharsetUtil.UTF_8);

在我的 SimpleChannelInboundHandler 中。它只适用于第一次查询,之后我开始有

WARNING: Failed to mark a promise as success because it has failed already: DefaultChannelPromise@48c81b24(failure: io.netty.handler.codec.EncoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1), unnotified cause:
io.netty.handler.codec.EncoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:106)
    at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738)
    at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:801)
    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 travel.ServerHandler.writeResult(ServerHandler.java:475)

看来缓冲区会在第一次回复后自动释放。 拥有这种缓冲区的正确方法是什么?

共享Netty缓冲区时,需要遵循basic reference counting的规则,不像基本垃圾回收的简单规则。

这些规则基本上归结为:

  • 从您的 class 发送 ByteBuf 时,调用 retain()
  • 如果您使用完 ByteBuf,请调用 release()

大多数时候,当你在发送它的同时使用完一个 bytebuf,你可以删除这两个调用。

在你的例子中,当你将你的共享 ByteBuf 写入套接字时,你应该调用 retain() 来增加引用计数,因为该对象现在在 2 个不同的地方使用。

在调用 .retain() 之后,您还需要做 1 个技巧,即调用 .duplicate(),因为这可以防止对 reader 索引的修改传递到您的基本副本,不这样做会出现第一次写入成功的问题,但之后所有后续写入都会写入一个空缓冲区。