在FixedLengthFrameDecoder中查看源码decode发现:如果字节满足条件后会返回in.readRetainedSlice(frameLength),这里用了retained,也就是说会把in的引用计数加1,但是在FixedLengthFrameDecoder中却没有发现把引用计数减1的地方。很疑惑为什么能做到内存不泄漏,所以继续查看其他源码。
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < frameLength) {return null;
} else {
return in.readRetainedSlice(frameLength);
}
}
在ByteToMessageDecoder中的channelRead发现:如过msg是ByteBuf类,那么会自动释放引用计数cumulation.release(),如果不是ByteBuf类,是不会释放引用计数,直接调用ctx.fireChannelRead(msg)。
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof ByteBuf) {
CodecOutputList out = CodecOutputList.newInstance();
try {
ByteBuf data = (ByteBuf) msg;
first = cumulation == null;
if (first) {
cumulation = data;
} else {
cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
}
callDecode(ctx, cumulation, out);
} catch (DecoderException e) {
throw e;
} catch (Throwable t) {
throw new DecoderException(t);
} finally {
if (cumulation != null && !cumulation.isReadable()) {
numReads = 0;
cumulation.release();
cumulation = null;
} else if (++ numReads >= discardAfterReads) {
// We did enough reads already try to discard some bytes so we not risk to see a OOME.
// See https://github.com/netty/netty/issues/4275
numReads = 0;
discardSomeReadBytes();
}
int size = out.size();
decodeWasNull = !out.insertSinceRecycled();
fireChannelRead(ctx, out, size);
out.recycle();
}
} else {
ctx.fireChannelRead(msg);
}
}
由此可见:如果需要自定义decode类(继承ByteToMessageDecoder),重写decode时,如果返回List<Object> out是ByteBuf类时,可以用retained,这样可以提高运行效率。如果不是ByteBuf类时,不能使用retained,否则会产生内存泄漏。