У меня проблемы с утечками на EmbeddedChannel
, который я использую для анализа необработанного ответа http в FullHttpResponse
. Во время анализа я заметил, что подсчет ссылок ByteBuf, который я посылаю в канал как «вход», ведет себя по-разному в зависимости от его реализации, что выглядит странно.
Для справки, вот метод, который я использую для анализа необработанный ввод:
private FullHttpResponse decodeHttpResponse(ByteBuf responseBuff) {
EmbeddedChannel channel = new EmbeddedChannel(new HttpResponseDecoder(), new HttpObjectAggregator(99999999));
try {
channel.writeInbound(responseBuff);
channel.flush();
channel.finish();
return channel.readInbound();
} finally {
channel.close();
channel.finishAndReleaseAll();
}
}
Давайте использовать простое ByteBuf
, которое я создаю из ответа http, который я ранее записал в файл, и проведу некоторое тестирование, вот мой вывод (числа - это счетчики ссылок объекта) :
>>>---------- Test with ByteBuf ------------<<<
>>> [buf] : 1
buf.retain()
>>> [buf] : 2
resp = decodeHttpResponse(cbuf) => io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpResponse
>>> [buf] : 2 // [1]
>>> [resp] : 1 //
resp.retain()
>>> [buf] : 2
>>> [resp] : 2
resp.release()
>>> [buf] : 2
>>> [resp] : 1
resp.release() //
>>> [buf] : 1 // [2]
>>> [resp] : 0 //
- [1]: Когда мы создаем
FullHttpResponse
, refCount на входе ByteBuf равен без изменений . - [2] : Когда
FullHttpResponse
освобождается (refCount достигает 0), он распространяет один единственный релиз на базовый ByteBuf .
OK, теперь давайте обернем этот входной ByteBuf в CompositeByteBuf
и использовать его для построения FullHttpResponse
:
>>>---------- Test with CompositeByteBuf ------------<<<
>>> [buf] : 1
buf.retain()
>>> [buf] : 2
cbuf = buf.alloc().compositeBuffer()
>>> [buf] : 2
>>> [cbuf] : 1
cbuf.addComponent(true, buf)
>>> [buf] : 2
>>> [cbuf] : 1
cbuf.retain()
>>> [buf] : 2
>>> [cbuf] : 2
resp = decodeHttpResponse(cbuf) => io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpResponse
>>> [buf] : 2 //
>>> [cbuf] : 1 // [1]
>>> [resp] : 1 //
resp.retain()
>>> [buf] : 2
>>> [cbuf] : 1
>>> [resp] : 2
resp.release()
>>> [buf] : 2
>>> [cbuf] : 1
>>> [resp] : 1
resp.release()
>>> [buf] : 2 //
>>> [cbuf] : 1 // [2]
>>> [resp] : 0 //
- [1]: когда мы создаем
FullHttpResponse
, refCount на входном ByteBuf уменьшается на на 1 . - [2]: когда освобождается
FullHttpResponse
( refCount достигает 0), он не распространяется на базовый CompositeByteBuf .
Это различие в поведении сбивает с толку и затрудняет правильный подсчет ссылок (это упрощенный пример в в реальном приложении, запутанность многослойных буферов делает это еще сложнее) ? Или это может быть даже ошибка, которую следует устранить?