Netty中ByteBuf的copy、duplicate、slice方法对比

Jdk注释翻译

/**
*返回ByteBuf的可读字节的拷贝。修改返回的ByteBuf内容与当前ByteBuf完全不会相互影响。
*此方法不会修改当前ByteBuf的readerIndex或writerIndex
**/
public abstract ByteBuf copy();
/**
*返回ByteBuf可读字节的一部分。 修改返回的ByteBuf或当前ByteBuf会影响彼此的内容,
*同时它们维护单独的索引和标记,此方法不会修改当前ByteBuf的readerIndex或writerIndex
*另请注意,此方法不会调用{@link #retain()},因此不会增加引用计数。
**/
public abstract ByteBuf duplicate();
/**
*返回共享当前ByteBuf信息的新ByteBuf,他们使用独立的readIndex writeIndex markIndex
*修改返回的ByteBuf或当前ByteBuf会影响彼此的内容,同时它们维护单独的索引和标记,
*此方法不会修改当前ByteBuf的readerIndex或writerIndex,
*另请注意,此方法不会调用{@link #retain()},因此不会增加引用计数
**/
public abstract ByteBuf slice();

实验验证

public class ByteBufTest {

    public static void main(String[] args) throws UnsupportedEncodingException {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(10);
        byteBuf.writeInt(126);
        byteBuf.writeInt(127);
        byteBuf.writeBytes(new byte[]{1});
        System.out.println("byteBuf readInt="+byteBuf.readInt());
        System.out.println("byteBuf readerIndex=" + byteBuf.readerIndex() + "| writeIndex=" + byteBuf.writerIndex() + "|capacity=" + byteBuf.capacity());
        //返回ByteBuf的可读字节的拷贝。修改返回的ByteBuf内容与当前ByteBuf完全不会相互影响。
        //此方法不会修改当前ByteBuf的readerIndex或writerIndex
        System.out.println("====================byteBuf.copy()==================");
        ByteBuf cByteBuf = byteBuf.copy();
        System.out.println("cByteBuf readerIndex=" + cByteBuf.readerIndex() + "| writeIndex=" + cByteBuf.writerIndex() + "|capacity=" + cByteBuf.capacity());
        System.out.println("byteBuf readerIndex=" + byteBuf.readerIndex() + "| writeIndex=" + byteBuf.writerIndex() + "|capacity=" + byteBuf.capacity());
        System.out.println("向cByteBuf中写入数据" + cByteBuf.setInt(0, 128));
        System.out.println("cByteBuf=" + cByteBuf.getInt(0) + "|cByteBuf=" + cByteBuf.getByte(4));
        System.out.println("byteBuf=" + byteBuf.getInt(0) + "|byteBuf=" + byteBuf.getInt(4) + "|byteBuf=" + byteBuf.getByte(8));
        //返回ByteBuf可读字节的一部分。 修改返回的ByteBuf或当前ByteBuf会影响彼此的内容,
        // 同时它们维护单独的索引和标记,此方法不会修改当前ByteBuf的readerIndex或writerIndex
        //另请注意,此方法不会调用{@link #retain()},因此不会增加引用计数。
        System.out.println("====================byteBuf.slice()==================");
        ByteBuf sByteBuf = byteBuf.slice();
        System.out.println("sByteBuf readerIndex=" + sByteBuf.readerIndex() + "| writeIndex=" + sByteBuf.writerIndex() + "|capacity=" + sByteBuf.capacity());
        System.out.println("byteBuf readerIndex=" + byteBuf.readerIndex() + "| writeIndex=" + byteBuf.writerIndex() + "|capacity=" + byteBuf.capacity());
        System.out.println("向sByteBuf中写入数据" + sByteBuf.setInt(0, 128));
        System.out.println("sByteBuf=" + sByteBuf.getInt(0) + "|sByteBuf=" + sByteBuf.getByte(4));
        System.out.println("byteBuf=" + byteBuf.getInt(0) + "|byteBuf=" + byteBuf.getInt(4) + "|byteBuf=" + byteBuf.getByte(8));
        //返回共享当前ByteBuf信息的新ByteBuf,他们使用独立的readIndex writeIndex markIndex
        //修改返回的ByteBuf或当前ByteBuf会影响彼此的内容,同时它们维护单独的索引和标记,
        // 此方法不会修改当前ByteBuf的readerIndex或writerIndex,
        //另请注意,此方法不会调用{@link #retain()},因此不会增加引用计数。
        System.out.println("====================byteBuf.duplicate()==================");
        ByteBuf dByteBuf = byteBuf.duplicate();
        System.out.println("dByteBuf readerIndex=" + dByteBuf.readerIndex() + "| writeIndex=" + dByteBuf.writerIndex() + "|capacity=" + dByteBuf.capacity());
        System.out.println("byteBuf readerIndex=" + byteBuf.readerIndex() + "| writeIndex=" + byteBuf.writerIndex() + "|capacity=" + byteBuf.capacity());
        System.out.println("向dByteBuf中写入数据" + dByteBuf.setInt(0, 100));
        System.out.println("dByteBuf=" + dByteBuf.getInt(0) + "|dByteBuf=" + dByteBuf.getInt(4) + "|dByteBuf=" + dByteBuf.getByte(8));
        System.out.println("byteBuf=" + byteBuf.getInt(0) + "|byteBuf=" + byteBuf.getInt(4) + "|byteBuf=" + byteBuf.getByte(8));
        dByteBuf.writeBytes(new byte[]{2});
        System.out.println("dByteBuf readerIndex=" + dByteBuf.readerIndex() + "| writeIndex=" + dByteBuf.writerIndex() + "|capacity=" + dByteBuf.capacity());
        System.out.println("byteBuf readerIndex=" + byteBuf.readerIndex() + "| writeIndex=" + byteBuf.writerIndex() + "|capacity=" + byteBuf.capacity());
        System.out.println("dByteBuf=" + dByteBuf.getInt(0) + "|dByteBuf=" + dByteBuf.getInt(4) + "|dByteBuf=" + dByteBuf.getByte(8) + "|dByteBuf=" + dByteBuf.getByte(9));
        System.out.println("byteBuf=" + byteBuf.getInt(0) + "|byteBuf=" + byteBuf.getInt(4) + "|byteBuf=" + byteBuf.getByte(8) + "|byteBuf=" + dByteBuf.getByte(9));
    }

}

执行结果:

byteBuf readInt=126
byteBuf readerIndex=4| writeIndex=9|capacity=10
====================byteBuf.copy()==================
cByteBuf readerIndex=0| writeIndex=5|capacity=5
byteBuf readerIndex=4| writeIndex=9|capacity=10
向cByteBuf中写入数据PooledUnsafeDirectByteBuf(ridx: 0, widx: 5, cap: 5)
cByteBuf=128|cByteBuf=1
byteBuf=126|byteBuf=127|byteBuf=1
====================byteBuf.slice()==================
sByteBuf readerIndex=0| writeIndex=5|capacity=5
byteBuf readerIndex=4| writeIndex=9|capacity=10
向sByteBuf中写入数据UnpooledSlicedByteBuf(ridx: 0, widx: 5, cap: 5/5, unwrapped: PooledUnsafeDirectByteBuf(ridx: 4, widx: 9, cap: 10))
sByteBuf=128|sByteBuf=1
byteBuf=126|byteBuf=128|byteBuf=1
====================byteBuf.duplicate()==================
dByteBuf readerIndex=4| writeIndex=9|capacity=10
byteBuf readerIndex=4| writeIndex=9|capacity=10
向dByteBuf中写入数据UnpooledDuplicatedByteBuf(ridx: 4, widx: 9, cap: 10, unwrapped: PooledUnsafeDirectByteBuf(ridx: 4, widx: 9, cap: 10))
dByteBuf=100|dByteBuf=128|dByteBuf=1
byteBuf=100|byteBuf=128|byteBuf=1
dByteBuf readerIndex=4| writeIndex=10|capacity=10
byteBuf readerIndex=4| writeIndex=9|capacity=10
dByteBuf=100|dByteBuf=128|dByteBuf=1|dByteBuf=2
byteBuf=100|byteBuf=128|byteBuf=1|byteBuf=2

小结:

  • duplicate():直接拷贝整个buffer,包括readerIndex、capacity、writerIndex
  • slice():拷贝buffer中已经写入数据的部分
  • copy()方法会进行内存复制工作,效率很低。

duplicate和copye这两个方法都属于浅拷贝它和原buffer是共享数据的。所以说调用这些方法消耗是很低的,
并没有开辟新的空间去存储,但是修改后会影响原buffer。这就会导致一个问题:在源ByteBuf调用release() 之后,
一旦引用计数为零,就变得不能访问了;在这种场景下,源ByteBuf的所有浅层复制实例也不能进行读写了;如果强行对浅层复制实例进行读写,则会报错。因此,在调用浅层复制实例时,可以通过调用一次retain() 方法来增加引用,表示它们对应的底层内存多了一次引用,引用计数为2。在浅层复制实例用完后,需要调用两次release()方法,将引用计数减一,这样就不影响源ByteBuf的内存释放。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值