下面是服务端基础结构,在channelRead处打断点,分析channel中msg的来源
@Slf4j
public class TestByteBuf {
public static void main(String[] args) {
ByteBufAllocator.DEFAULT.buffer();
new ServerBootstrap()
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
ch.pipeline().addLast(new LoggingHandler());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
/**打断点**/ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// ByteBuf buf = ctx.alloc().buffer();
// log.debug("alloc buf {}", buf);
log.debug("receive buf {}", msg);
System.out.println("");
}
});
}
}).bind(8080);
}
}
需要一个客户端来触发
@Slf4j
public class TestBacklogClient {
public static void main(String[] args) {
NioEventLoopGroup worker = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(worker);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(ctx.alloc().buffer().writeBytes("hello!".getBytes()));
}
});
}
});
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.error("client error", e);
} finally {
worker.shutdownGracefully();
}
}
}
我们msg的类型为:PooledUnsafeDirectByteBuf
池化并使用直接内存的字节缓冲数组
沿着调用链往前找,跳过Handler,跳过PipeLine,找到初始位置msg生成的部分
这里定位到AbstractNioByteChannel类
找到和msg相同类型的byteBuf,就是这块
网上跳,发现byteBuf的分配方式如下
byteBuf = allocHandle.allocate(allocator);
我们分三个方面跟踪
1.确定池化/非池化
上文的allocator是使用
final ByteBufAllocator allocator = config.getAllocator();
我们一直向上跟
ChannelConfig.getAllocator()->DefaultChannelConfig.getAllocator()->ByteBufAllocator.DEFAULT->ByteBufUtil.DEFAULT_ALLOCATOR
然后是下面:可以清晰的看到使用逻辑是unpooled
static final ByteBufAllocator DEFAULT_ALLOCATOR;
static {
String allocType = SystemPropertyUtil.get(
"io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
allocType = allocType.toLowerCase(Locale.US).trim();
ByteBufAllocator alloc;
if ("unpooled".equals(allocType)) {
alloc = UnpooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: {}", allocType);
} else if ("pooled".equals(allocType)) {
alloc = PooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: {}", allocType);
} else {
alloc = PooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
}
DEFAULT_ALLOCATOR = alloc;
2.确定使用直接内存/堆内存
Step Into跟踪allocate方法,找到如下分配内存方式,使用ioBuffer为直接内存
@Override
public ByteBuf allocate(ByteBufAllocator alloc) {
return alloc.ioBuffer(guess());
}
3.确定初始容量
跟踪recvBufAllocHandle()方法
AbstractChannel.recvBufAllocHandle()->ChannelConfig.getRecvByteBufAllocator()->DefaultChannelConfig.getRecvByteBufAllocator()->setRecvByteBufAllocator()->DefaultChannelConfig()->AdaptiveRecvByteBufAllocator.AdaptiveRecvByteBufAllocator()
然后找到如下
//控制大小
public AdaptiveRecvByteBufAllocator() {
this(DEFAULT_MINIMUM, DEFAULT_INITIAL, DEFAULT_MAXIMUM);
}
static final int DEFAULT_MINIMUM = 64;
static final int DEFAULT_INITIAL = 1024;
static final int DEFAULT_MAXIMUM = 65536;
确定了msg的初始容量为1024