【Netty】高性能原因:直接内存与零拷贝

Netty 的接收和发送 ByteBuffer 采用 DIRECT BUFFERS,使用堆外直接内存进行 Socket 读写,不需要进行字节缓冲区的二次拷贝。

PS:关于直接内存可以参考我的这篇文章…不清楚的同学一定要看,因为 Netty 就是通过直接内存实现的零拷贝。

如果使用传统的 JVM 堆内存(HEAP BUFFERS)进行 Socket 读写,JVM 会将堆内存 Buffer 拷贝一份到直接内存中,然后才能写入Socket 中。JVM 堆内存的数据是不能直接写入 Socket 中的。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。

可以看下 Netty 的读写源码,比如 read 源码 NioByteUnsafe.read():

顺着 do while 中的 allocHandle.allocate(allocator) 一路向下点,最终走到了 AbstractByteBufAllocator 的 ioBuffer() 方法中:

如果我们顺着上面的 directBuffer() 再点下去,会走到 PooledUnsafeDirectByteBuf#initMemoryAddress(),这个方法其实就很清楚,创建直接内存的关键是它的起始地址,而基于堆内存 Buffer(比如IntBuffer、LongBuffer等)核心的一个暂存数据的成员数组。

总结一下,相当于是每次循环读取一次消息,就通过 ByteBufferAllocator 的 ioBuffer 方法获取 ByteBuf 对象。当进行 Socket IO 读写的时候,为了避免直接内存->堆内存->直接内存的两次拷贝,Netty 的 ByteBuf 分配器直接创建非堆内存,通过“零拷贝”来提升读写性能。

PS:这里的堆内存也可以理解成用户空间,直接内存理解成内核空间


另外,Netty 的文件传输采用了 transferTo() 方法,它可以直接将文件缓冲区的数据发送到目标 Channel,避免了传统通过循环 write() 方式导致的内存拷贝问题。

// DefaultFileRegion 
public long transferTo(WritableByteChannel target, long position) throws IOException {
    long count = this.count - position;
    if (count < 0 || position < 0) {
        throw new IllegalArgumentException(
                "position out of range: " + position +" (expected: 0 - " + (this.count - 1) + ')');
    }
    if (count == 0) {
        return 0L;
    }
    if (refCnt() == 0) {
        throw new IllegalReferenceCountException(0);
    }
    // Call open to make sure fc is initialized. This is a no-oop if we called it before.
    open();
	
	// transferTo
    long written = file.transferTo(this.position + position, count, target);
    if (written > 0) {
        transferred += written;
    }
    return written;
}

对于很多操作系统它直接将文件缓冲区的内容发送到目标 Channel 中,而不需要通过拷贝的方式,这是一种更加高效的传输方式,它实现了文件传输的“零拷贝”。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A minor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值