关于我的自定义净值解码器中的java:IllegalReferenceCount

IllegalReferenceCount in my custom netty Decoder

我刚开始使用Netty(使用4.0.15.Final)。我想从使用专有协议的现有硬件设备中读取消息。我已经实现了如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class Xml2StreamProtocolDecoder extends ByteToMessageDecoder
{
    private static final int LENGTH_OF_START_SENTINEL_IN_BYTES = 1;
    private static final int LENGTH_OF_END_SENTINEL_IN_BYTES = 1;
    private static final int LENGTH_OF_LENGTH_FIELD_IN_BYTES = 4;

    @Override
    protected void decode( ChannelHandlerContext ctx, ByteBuf in, List<Object> out ) throws Exception
    {
        if( in.readableBytes() > LENGTH_OF_START_SENTINEL_IN_BYTES + LENGTH_OF_LENGTH_FIELD_IN_BYTES)
        {
            short startSentinel = in.readUnsignedByte();
            if (startSentinel != 0x01)
            {
                throw new CorruptedFrameException("startsentinel not as expected, was" + startSentinel +" while we expect 0x01" );
            }

            int messageLength = getMessageLength( in );
            if( in.readableBytes() >= messageLength + LENGTH_OF_END_SENTINEL_IN_BYTES )
            {
                ByteBuf result = in.slice( in.readerIndex(), messageLength );
                in.skipBytes( messageLength );
                short endSentinel = in.readUnsignedByte();
                if( endSentinel != 0x00 )
                {
                    throw new CorruptedFrameException("endsentinel not as expected, was" + endSentinel +" while we expect 0x00" );
                }
                out.add( result );
            }
            else
            {
                // Not enough bytes yet in the frame. Wait on next pass with more bytes.
            }
        }
        else
        {
            // Not enough bytes yet to read out the length of the frame. Wait on next pass with more bytes.
        }
    }

    private int getMessageLength( ByteBuf in )
    {
        int msglen1 = in.readUnsignedByte();
        int msglen2 = in.readUnsignedByte();
        int msglen3 = in.readUnsignedByte();
        int msglen4 = in.readUnsignedByte();

        return ((msglen4 * 256 * 256 * 256) + (msglen3 * 256 * 256) + (msglen2 * 256) + msglen1);
    }
}

我有一个可以像这样正常工作的单元测试:

1
2
3
4
5
6
ByteBuf input = Unpooled.buffer();
input.writeBytes( .... );
Xml2StreamProtocolDecoder decoder = new Xml2StreamProtocolDecoder();
EmbeddedChannel channel = new EmbeddedChannel( decoder );
channel.writeInbound( input );
assertThat(channel.inboundMessages()).isNotNull().hasSize( 2 );

但是,当我在管道中添加第二个解码器(这是标准的Netty类)以将字节转换为这样的String时:

1
2
EmbeddedChannel channel = new EmbeddedChannel( decoder,
                                               new StringDecoder( Charset.forName("UTF-8" ) ) );

然后单元测试失败,但出现以下异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
Feb 25, 2014 10:11:26 AM io.netty.channel.embedded.EmbeddedChannel recordException
WARNING: More than one exception was raised. Will report only the first one and log others.
io.netty.handler.codec.DecoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:153)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
    at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169)
    at com.flir.its.test.Xml2StreamProtocolDecoder2Test.testWith2Messages(Xml2StreamProtocolDecoder2Test.java:188)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:640)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:627)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:798)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1102)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:137)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:121)
    at org.testng.TestRunner.runWorkers(TestRunner.java:1009)
    at org.testng.TestRunner.privateRun(TestRunner.java:683)
    at org.testng.TestRunner.run(TestRunner.java:553)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:311)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:306)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:268)
    at org.testng.SuiteRunner.run(SuiteRunner.java:217)
    at org.testng.TestNG.runSuite(TestNG.java:1062)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:956)
    at org.testng.TestNG.run(TestNG.java:874)
io.netty.handler.codec.DecoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:153)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
    at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169)
    at com.flir.its.test.Xml2StreamProtocolDecoder2Test.testWith2Messages(Xml2StreamProtocolDecoder2Test.java:188)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:640)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:627)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:798)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1102)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:137)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:121)
    at org.testng.TestRunner.runWorkers(TestRunner.java:1009)
    at org.testng.TestRunner.privateRun(TestRunner.java:683)
    at org.testng.TestRunner.run(TestRunner.java:553)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:311)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:306)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:268)
    at org.testng.SuiteRunner.run(SuiteRunner.java:217)
    at org.testng.TestNG.runSuite(TestNG.java:1062)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:956)
    at org.testng.TestNG.run(TestNG.java:874)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:75)
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:120)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:115)
    at io.netty.buffer.AbstractDerivedByteBuf.release(AbstractDerivedByteBuf.java:50)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:91)
    ... 35 more
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:75)
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:120)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:115)
    at io.netty.buffer.AbstractDerivedByteBuf.release(AbstractDerivedByteBuf.java:50)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:91)
    ... 35 more

为什么会这样?我在Xml2StreamProtocolDecoder中做错了吗?


看看ByteBuf :: retain()