После часов экспериментов и отладки в исходном коде, о 4-м пункте:
ReferenceCountUtil.refCnt
public static int refCnt(Object msg) {
return msg instanceof ReferenceCounted ? ((ReferenceCounted) msg).refCnt() : -1;
}
, поскольку каждый обработчик netty является ответственным шаблоном цепочки, write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
может фактически иметь любой объект msg (аргумент, передаваемый по цепочке). В этой ситуации нужно только вручную вызвать релиз:
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
FullHttpResponse fullHttpResponse = ...
ctx.write(fullHttpResponse, promise);
}
Инстанцирование FullHttpResponse
наконец вызывает ByteBuffer.allocate
, который идет с refCnt плюс 1.
Если в следующих обработчиках, из-за исключений или userFiredEvents
, это FullHttpResponse
не отправляется путем вызова:
ctx.write(msg, promise);
ctx.flush();
, затем FullHttpResponse
необходимо разблокировать вручную. Последнее, но не менее важное: если FullHttpResponse
выпустил refCnt, он не будет отправлен. С точки зрения клиента запрос зависает.