netty - ReplayingDecoder 中的 ResourceLeakDetector 异常。我什么时候释放ByteBuf?

标签 netty

我在扩展 ReplayingDecoder 的 DecodeEventHandler 类中遇到 ResourceLeakDetector 异常。我很难理解应该何时何地释放任何方法的 BytBuf。是否需要释放传递过来的ByteBuf?我尝试释放 header、eventBody 和 AttachedData ByteBuf 对象,但这在我的代码中后来产生了问题。代码是...

protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception
{
    switch (state())
    {
        case READ_HEADER:
            ByteBuf header = byteBuf.readBytes(BaseEvent.EVENT_HEADER_SIZE);
            newEvent = new BaseEvent(header.nioBuffer());
            checkpoint(EventDecoderState.READ_BODY);
            // Fall through

        case READ_BODY:
            ByteBuf eventBody = byteBuf.readBytes(newEvent.getEventHeaderBodySize() - BaseEvent.EVENT_HEADER_SIZE);
            newEvent.setEventBody(eventBody.nioBuffer());
            checkpoint(EventDecoderState.READ_ATTACHED_DATA);
            // Fall through

        case READ_ATTACHED_DATA:
            ByteBuf attachedData = byteBuf.readBytes(newEvent.getAttachedDataSize());
            newEvent.clearAttachedData();
            newEvent.addAttachedData(attachedData.nioBuffer());
            list.add(newEvent);
            checkpoint(EventDecoderState.READ_HEADER);
    }
}

该方法从第 23 行开始。我收到的异常是...

2016-06-07 13:30:49.783 [ERROR] (nioEventLoopGroup-7-1) io.netty.util.ResourceLeakDetector  - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 2
#2:
    io.netty.buffer.AdvancedLeakAwareByteBuf.nioBuffer(AdvancedLeakAwareByteBuf.java:669)
    com.oakgate.netty.DecodeEventHandler.decode(DecodeEventHandler.java:30)
    io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:376)
    io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:245)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:1078)
    io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:117)
    io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:527)
    io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:484)
    io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:398)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:370)
    io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:742)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:145)
    java.lang.Thread.run(Thread.java:745)
#1:
    io.netty.buffer.AdvancedLeakAwareByteBuf.writeBytes(AdvancedLeakAwareByteBuf.java:561)
    io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:790)
    io.netty.handler.codec.ReplayingDecoderByteBuf.readBytes(ReplayingDecoderByteBuf.java:576)
    com.oakgate.netty.DecodeEventHandler.decode(DecodeEventHandler.java:29)
    io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:376)
    io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:245)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:1078)
    io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:117)
    io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:527)
    io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:484)
    io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:398)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:370)
    io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:742)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:145)
    java.lang.Thread.run(Thread.java:745)
Created at:
    io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:271)
    io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:179)
    io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:115)
    io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:789)
    io.netty.handler.codec.ReplayingDecoderByteBuf.readBytes(ReplayingDecoderByteBuf.java:576)
    com.oakgate.netty.DecodeEventHandler.decode(DecodeEventHandler.java:29)
    io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:376)
    io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:245)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
    io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:354)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:145)
    io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:1078)
    io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:117)
    io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:527)
    io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:484)
    io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:398)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:370)
    io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:742)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:145)
    java.lang.Thread.run(Thread.java:745)

其他信息

当我释放通过调用 byteBuf.readBytes() 创建的每个 ByteBuf( header 、eventBody 和 AttachedData)时,我稍后在处理事件时会遇到问题。我调用 nioBuffer() 从 ByteBuf 创建一个 ByteBuffer,看起来释放原始 ByteBuf 会影响 ioBuffer() 调用中的 ByteBuffer。根据文档,返回的缓冲区与 bytebuf 共享内容,这很可能意味着我还无法释放它。我是否需要保留每个 ByteBuf,然后在处理事件时释放它?除非有其他方法可以做到这一点,否则看起来就是这样。

最佳答案

您正在通过 byteBuf.readBytes 创建新的 ByteBuf,它们需要被释放。

您的案例READ_HEADER示例::

case READ_HEADER:
    ByteBuf header = null;
    try {
        header = byteBuf.readBytes(BaseEvent.EVENT_HEADER_SIZE);
        newEvent = new BaseEvent(header.nioBuffer());
        checkpoint(EventDecoderState.READ_BODY);
    } finally {
        if(header != null) 
            header.release();
    }
    // Fall through

关于netty - ReplayingDecoder 中的 ResourceLeakDetector 异常。我什么时候释放ByteBuf?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37690912/

相关文章:

java - 如何修复maven检查样式错误

java - 在 Netty 中处理消息

java - WebFlux DataBufferLimitException : Part headers exceeded the memory usage limit of 8192 bytes

java - netty echo 服务器发送消息,但我没有看到它

android - Akka Remoting 是否仅支持单向连接?

java - 一个 netty 缓冲区问题中包含多条消息

java - 在两个网络 channel 之间传播背压

apache-spark - Spark 2.3.0 netty版本问题: NoSuchMethod io.netty.buffer.PooledByteBufAllocator.metric()

java - 需要可靠/持久的出站套接字,选项?

netty - Apache Storm java.nio.channels.ClosedChannelException : null