일반적인 ChannelInboundHandler에서 ByteBuf refCnt 자동 감소 현상

79 views
Skip to first unread message

이화평

unread,
Jul 8, 2023, 6:26:04 AM7/8/23
to Netty Korean User Group
안녕하세요.  netty 입문한지 얼마 안된 뉴비입니다.
SimpleChannelInbound를 사용하거나 write를 하는 경우에는 ByteBuf의 refCnt가 자동으로 감소하는건 알고 있습니다.

그런데, 단순히 ChannelInboundhandlerAdaptor 를 상속한 커스텀 핸들러에서 fireChannelRead 메소드를 호출하니 refCnt가 자동으로 감소하는 이상한..? 현상을 겪고있습니다.

우선 파이프라인에 InboundHandler1와 InboundHandler2를 등록했습니다.

pipeline.addLast(new InboundHandler1());
pipeline.addLast(new InboundHandler2());

그리고 각 핸들러는 아래와 같이 구현되어있습니다.

public class InboundHandler1 extends ChannelInboundHandlerAdapter {

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("InboundHandler1 ref : " + buf.refCnt());
ctx.fireChannelRead(buf);
System.out.println("InboundHandler1 ref : " + buf.refCnt());
}
}

public class InboundHandler2 extends ChannelInboundHandlerAdapter {

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("InboundHandler2 ref : " + buf.refCnt());
ctx.fireChannelRead(buf);
System.out.println("InboundHandler2 ref : " + buf.refCnt());
}
}

이 상황에서 클라이언트가 메시지를 보내면, 예상했던 결과와는 다르게 아래와 같이 나옵니다.
모든 refCnt를 출력하는 부분에서 1이 나와야한다고 생각했는데 0으로 나오더라구요.
도움주시면 감사하겠습니다.

```
InboundHandler1 ref : 1
InboundHandler2 ref : 1
InboundHandler2 ref : 0
InboundHandler1 ref : 0
``

Joo Sing

unread,
Jul 8, 2023, 8:50:46 AM7/8/23
to Netty Korean User Group
안녕하세요.

Netty에는 우리가 파이프라인에 등록한 핸들러 외에 숨겨진 일종의 핸들러가 두 개(TailContext, HeadContext)가 더 있더라구요.

pipeline.addLast(new InboundHandler1()); // #1
pipeline.addLast(new InboundHandler2()); // #2

이렇게 구성된 파이프라인에서 마지막 핸들러인 #2에서 다음 핸들러로 메시지를 던지면 최종적으로 TailContext 라는 곳에서 메시지를 다루게 되는데, 거기서  ReferenceCountUtil.release(msg) 코드가 한 번 더 호출됩니다. 아래 관련된 DefaultChannelPipeline 클래스를 요약해 보았는데 디버그 모드로 한 번 따라가 보면 이해에 도움이 되실 것 같아요. 

public class DefaultChannelPipeline implements ChannelPipeline {
    ...
    final AbstractChannelHandlerContext head;
    final AbstractChannelHandlerContext tail;
    ...
    final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
        ...
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            onUnhandledInboundMessage(ctx, msg);
        }
    }
    ...
    protected void onUnhandledInboundMessage(Object msg) {
        try {
            ...
        } finally {
            ReferenceCountUtil.release(msg); // <------------------------------------ 여기서 호출 됨
        }
    }
}

2023년 7월 8일 토요일 오후 7시 26분 4초 UTC+9에 leeg...@gmail.com님이 작성:
Reply all
Reply to author
Forward
0 new messages