ReplayingDecoder中的ResourceLeakDetector异常。我什么时候发布ByteBuf?

时间:2016-06-07 23:12:59

标签: 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()(header,eventBody和attachedData)创建的每个ByteBuf时,我会在以后处理事件时遇到问题。我调用nioBuffer()从ByteBuf创建一个ByteBuffer,看起来释放原始的ByteBuf会影响ioBuffer()调用的ByteBuffer。根据文档,返回的缓冲区与bytebuf共享内容,这很可能意味着我还不能释放它。我是否需要保留每个ByteBuf,然后在处理事件时释放?除非有其他方法可以做到这一点,否则就会出现这种情况。

1 个答案:

答案 0 :(得分:1)

您正在通过ByteBuf创建新的byteBuf.readBytes,需要将其发布。

case 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