Netty之ByteBuf解读(下)

简介: Netty之ByteBuf解读(下)

这时调用 slice 进行切片,无参 slice 是从原始 ByteBuf 的 read index 到 write index 之间的内容进行切片,切片后的 max capacity 被固定为这个区间的大小,因此不能追加 write

1. ByteBuf slice = origin.slice();
2. System.out.println(ByteBufUtil.prettyHexDump(slice));
3. // slice.writeByte(5); 如果执行,会报 IndexOutOfBoundsException 异常
1.          +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 02 03 04                                        |...             |
5. +--------+-------------------------------------------------+----------------+

如果原始 ByteBuf 再次读操作(又读了一个字节)

1. origin.readByte();
2. System.out.println(ByteBufUtil.prettyHexDump(origin));

这时的 slice 不受影响,因为它有独立的读写指针

1.          +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 02 03 04                                        |...             |
5. +--------+-------------------------------------------------+----------------+

如果 slice 的内容发生了更改

1. slice.setByte(2, 5);
2. System.out.println(ByteBufUtil.prettyHexDump(slice));
1.          +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 02 03 05                                        |...             |
5. +--------+-------------------------------------------------+----------------+

这时,原始 ByteBuf 也会受影响,因为底层都是同一块内存

System.out.println(ByteBufUtil.prettyHexDump(origin));
1.          +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 03 05                                           |..              |
5. +--------+-------------------------------------------------+----------------+

其他拷贝方式 duplicate& copy&CompositeByteBuf

duplicate

【零拷贝】的体现之一,就好比截取了原始 ByteBuf 所有内容,并且没有 max capacity 的限制,也是与原始 ByteBuf 使用同一块底层内存,只是读写指针是独立的

copy

会将底层内存数据进行深拷贝,因此无论读写,都与原始 ByteBuf 无关

CompositeByteBuf

【零拷贝】的体现之一,可以将多个 ByteBuf 合并为一个逻辑上的 ByteBuf,避免拷贝

有两个 ByteBuf 如下

1. ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer(5);
2. buf1.writeBytes(new byte[]{1, 2, 3, 4, 5});
3. ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer(5);
4. buf2.writeBytes(new byte[]{6, 7, 8, 9, 10});
5. System.out.println(ByteBufUtil.prettyHexDump(buf1));
6. System.out.println(ByteBufUtil.prettyHexDump(buf2));
1.          +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 01 02 03 04 05                                  |.....           |
5. +--------+-------------------------------------------------+----------------+
6.          +-------------------------------------------------+
7.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
8. +--------+-------------------------------------------------+----------------+
9. |00000000| 06 07 08 09 0a                                  |.....           |
10. +--------+-------------------------------------------------+----------------+

现在需要一个新的 ByteBuf,内容来自于刚才的 buf1 和 buf2,如何实现?

方法1:

1. ByteBuf buf3 = ByteBufAllocator.DEFAULT
2.     .buffer(buf1.readableBytes()+buf2.readableBytes());
3. buf3.writeBytes(buf1);
4. buf3.writeBytes(buf2);
5. System.out.println(ByteBufUtil.prettyHexDump(buf3));

结果

1. +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 01 02 03 04 05 06 07 08 09 0a                   |..........      |
5. +--------+-------------------------------------------------+----------------+

这种方法好不好?

回答:是不太好,因为进行了数据的内存复制操作

方法2:

1. CompositeByteBuf buf3 = ByteBufAllocator.DEFAULT.compositeBuffer();
2. // true 表示增加新的 ByteBuf 自动递增 write index, 否则 write index 会始终为 0
3. buf3.addComponents(true, buf1, buf2);

结果是一样的

1. +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 01 02 03 04 05 06 07 08 09 0a                   |..........      |
5. +--------+-------------------------------------------------+----------------+

CompositeByteBuf 是一个组合的 ByteBuf,它内部维护了一个 Component 数组,每个 Component 管理一个 ByteBuf,记录了这个 ByteBuf 相对于整体偏移量等信息,代表着整体中某一段的数据。

  • 优点,对外是一个虚拟视图,组合这些 ByteBuf 不会产生内存复制
  • 缺点,复杂了很多,多次操作会带来性能的损耗

Unpooled

Unpooled 是一个工具类,类如其名,提供了非池化的 ByteBuf 创建、组合、复制等操作

这里仅介绍其跟【零拷贝】相关的 wrappedBuffer 方法,可以用来包装 ByteBuf

1. ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer(5);
2. buf1.writeBytes(new byte[]{1, 2, 3, 4, 5});
3. ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer(5);
4. buf2.writeBytes(new byte[]{6, 7, 8, 9, 10});
5. 
6. // 当包装 ByteBuf 个数超过一个时, 底层使用了 CompositeByteBuf
7. ByteBuf buf3 = Unpooled.wrappedBuffer(buf1, buf2);
8. System.out.println(ByteBufUtil.prettyHexDump(buf3));
1.          +-------------------------------------------------+
2.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
3. +--------+-------------------------------------------------+----------------+
4. |00000000| 01 02 03 04 05 06 07 08 09 0a                   |..........      |
5. +--------+-------------------------------------------------+----------------+

也可以用来包装普通字节数组,底层也不会有拷贝操作


1. ByteBuf buf4 = Unpooled.wrappedBuffer(new byte[]{1, 2, 3}, new byte[]{4, 5, 6});
2. System.out.println(buf4.getClass());
3. System.out.println(ByteBufUtil.prettyHexDump(buf4));
1. class io.netty.buffer.CompositeByteBuf
2. +-------------------------------------------------+
3.          |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
4. +--------+-------------------------------------------------+----------------+
5. |00000000| 01 02 03 04 05 06                               |......          |
6. +--------+-------------------------------------------------+----------------+

 


相关文章
|
4月前
|
Java API 容器
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf
113 0
|
Java API 开发者
Netty详解ByteBuf
Netty详解ByteBuf
92 0
|
3月前
netty查看ByteBuf工具
netty查看ByteBuf工具
|
4月前
|
Java API 索引
Netty Review - ByteBuf 读写索引 详解
Netty Review - ByteBuf 读写索引 详解
147 1
|
4月前
|
API 容器
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf(一)
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf
62 0
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf(一)
|
4月前
|
Java API
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf(二)
《跟闪电侠学Netty》阅读笔记 - 数据载体ByteBuf
53 0
|
存储 Java Linux
Netty ByteBuf 的零拷贝(Zero Copy)详解
Netty ByteBuf 的零拷贝(Zero Copy)详解
204 0
Netty之ByteBuf解读(中)
Netty之ByteBuf解读(中)
|
缓存 算法 Java
|
前端开发 算法 Java
Netty组件Future、Promise、Handler、Pipline、ByteBuf
Netty组件Future、Promise、Handler、Pipline、ByteBuf
143 0