Netty утечка памяти для http-сервера. Когда выпустить сообщение? - PullRequest
0 голосов
/ 05 июля 2018

Если не используется SimpleChannelInboundHandler channelRead0, следует освобождать входные пакеты, если ctx.fireChannelRead не вызывается.

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    log.error("receive {}", msg);
    if (msg instanceof FullHttpRequest) {            
        FullHttpRequest req = (FullHttpRequest) msg;
        ReferenceCountUtil.release(msg);
        clientChannel.writeAndFlush(new RequestWrapper(req, foo)); 
    }
}

clientChannel.writeAndFlush в случае успеха, нажмите requestWrapper в очередь. netty не показывает LEAK warnings, но, как описано в jvm out of memory , Old Gener этого проекта увеличивается, событие с ReferenceCountUtil.release(msg).

  1. если входное сообщение http не выпущено, почему официальный пример не вызывает явно вызов release?
  2. в channelRead, если полученное сообщение установлено в другом bean-компоненте, а затем этот bean-компонент передается ctx.fireChannelRead, я должен вызвать release для этого сообщения, как в коде выше?
  3. если новый объект передан ctx.fireChannelRead(newObject), я должен вызвать release(newObject) в следующем обработчике?

вот так:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    ctx.fireChannelRead("hello world");
}

public void channelRead(ChannelHandlerContext ctx, Object msg) {
    assert "hello world".equals(msg);
    ReferenceCountUtil.release(msg); // is this necessary if it is created in the former handler?
}
  1. Как насчет операции записи, я также должен вызывать release для объекта записи?

вот так:

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    ctx.write("bye", promise);
}

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    assert "bye".equals(msg);
    // should I call ReferenceCountUtil.release(msg); ?
    ctx.write(“bye bye”, promise);
}

Ответы [ 2 ]

0 голосов
/ 09 июля 2018

После часов экспериментов и отладки в исходном коде, о 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, он не будет отправлен. С точки зрения клиента запрос зависает.

0 голосов
/ 07 июля 2018

1.Может быть, это ошибка. Честно говоря, я не знаю. Но она должна освободить obj, если вы не вызываете ctx.fireChannelRead () в вашем обработчике (прерывайте цепочку обработчиков) , Или TailContext освободит объект.

2.Вы не можете выпустить сообщение в этом обработчике, если вы это сделаете, возможно, другой контекст выделит объект, который используется в этом контексте. Вы должны освободить объект, только если bean-компонент завершен;

3.Ваш новый объект не реализован ReferenceCounting , так зачем вам нужно освобождать объект? Просто верните false, но ничего не делайте в ReferenceCountUtil следующим образом:

    public static boolean release(Object msg) {
    if (msg instanceof ReferenceCounted) {
        return ((ReferenceCounted) msg).release();
    }
    return false;
}

4. Вам не нужно освобождать объект записи , поскольку netty будет освобождать после отправки объекта

...