三行代码看懂Netty零拷贝

Netty的零拷贝区别于操作系统的零拷贝,而更偏向于一种数据处理过程中的优化操作

Netty的Zero-copy体现在如下几个方面:

  • Netty提供了CompositeByteBuf类,它可以将多个ByteBuf合并为一个逻辑上的ByteBuf,避免了各个ByteBuf之间的拷贝。
  • 通过wrap操作,我们可以将byte[]数组、ByteBuf、 ByteBuffer 等包装成一个 Netty ByteBuf对象,进而避免了拷贝操作。
  • ByteBuf支持slice 操作,因此可以将ByteBuf分解为多个共享同一个存储区域的ByteBuf,避免了内存的拷贝。
  • 通过FileRegion包装的FileChannel.tranferTo实现文件传输,可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。

现在我们来用wrap举个例子简单分析下:

byte[] b1 = new byte[]{1, 2};
// 直接使用Unpooled.buffer()
ByteBuf buf = Unpooled.buffer(b1.length);
buf.writeBytes(b1);
b1[0] = 0;	// 改变数组,观察buf对象是否受其影响
System.out.println("===1 : b1 = " + Arrays.toString(b1));
System.out.println("===1 : buf1 = " + buf.readByte());
System.out.println("===1 : buf2 = " + buf.readByte());
//	使用wrap操作
ByteBuf buf1 = Unpooled.wrappedBuffer(b1);
b1[0] = 3; // 改变数组,观察buf对象是否受其影响
System.out.println("===2 : b1 = " + Arrays.toString(b1));
System.out.println("===2 : buf1 = " + buf1.readByte());
System.out.println("===2 : buf2 = " + buf1.readByte());
// 打印结果
===1 : b1 = [0, 2]
===1 : buf1 = 1
===1 : buf2 = 2
===2 : b1 = [3, 2]
===2 : buf1 = 3
===2 : buf2 = 2

对比结果很明显,wrap操作时,当数组b1发生变化,buf1对象也会相应发生改变,而buffer()则不受影响。

我们来简单看下二者具体操作:

public static ByteBuf buffer(int initialCapacity) {
    return ALLOC.heapBuffer(initialCapacity);
}

buffer()会在堆内存中新开辟一块长度为 initialCapacity 的内存空间,用来存储b1,这样当我们对数组b1进行改变操作时,显然buf对象不会受其影响,接下来我们对比下wrap操作:

public static ByteBuf wrappedBuffer(byte[] array) {
    if (array.length == 0) {
        return EMPTY_BUFFER;
    }
    return new UnpooledHeapByteBuf(ALLOC, array, array.length);
}

protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
        super(maxCapacity);

        checkNotNull(alloc, "alloc");
        checkNotNull(initialArray, "initialArray");

        if (initialArray.length > maxCapacity) {
            throw new IllegalArgumentException(String.format(
                    "initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
        }
  
        this.alloc = alloc;
        setArray(initialArray);
        setIndex(0, initialArray.length);
    }

由此可见,wrap会将数组b1直接存放到 UnpooledHeapByteBuf 对象中,从而避免了直接进行拷贝操作。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页