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 索引的修改传递到您的基本副本,不这样做会出现第一次写入成功的问题,但之后所有后续写入都会写入一个空缓冲区。
我有一个 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 索引的修改传递到您的基本副本,不这样做会出现第一次写入成功的问题,但之后所有后续写入都会写入一个空缓冲区。