- ByteBuf
- PooledByteBuf对象、内存复用
- 零拷贝机制
1 ByteBuf
- ByteBuf操作
- ByteBuf动态扩容
- 选择合适的ByteBuf实现
1.1 ByteBuf操作
ByteBuf三个重要属性:capacity容量、readerIndex读取位置、writerIndex写入位置。提供了两个指针变量来支持顺序读和写操作,分别是读操作readerIndex和写操作writerIndex。
下图显示一个缓冲区是如何被两个指针分割成三个区域的:
1.2 ByteBuf动态扩容
capacity默认值:256字节、最大值:Integer.MAX_VALUE(2GB)
write*方法调用时,通过AbstractByteBuf.ensureWritable0进行检查。容量计算方法:AbstractByteBufAllocator.calculateNewCapacity(新capacity的最小要求,capacity最大值)
根据新capacity的最小值要求,对应有两套计算方法:
没超过4兆:从64字节开始,每次增加一倍,直至计算出来的newCapacity满足新容量最小要求。
示例:当前大小256,已写250,继续写10字节数据,需要的容量最小要求是261,则新容量是6422*2=512
超过4兆:新容量 = 新容量最小要求 / 4兆 * 4兆 + 4兆
示例:当前大小3兆,已写3兆,继续写2兆数据,需要的容量最小要求是5兆,则新容量是8兆(不能超过最大值)
1.3 选择合适的ByteBuf实现
了解核心的:3个维度的划分方式,8种具体实现
堆内/堆外 | 是否池化 | 访问方式 | 具体实现类 | 备注 |
---|---|---|---|---|
heap堆内 | unpool | safe | UnpooledHeapByteBuf | 数组实现 |
unsafe | UnpooledUnsafeHeapByteBuf | Unsafe类直接操作内存 | ||
pool | safe | PooledHeapByteBuf | ||
unsafe | PooledUnsafeHeapByteBuf | |||
direct堆外 | unpool | safe | UnpooledDirectByteBuf | NIO DirectByteBuffer |
unsafe | UnpooledUnsafeDirectByteBuf | |||
pool | safe | PooledDirectByteBuf | ||
unsafe | PooledUnsafeDirectByteBuf |
在使用中,都是通过ByteBufAllocator分
配器进行申请的,同时分配器具备有内存管理的功能
2 PooledByteBuf对象、内存复用
PoolThreadCache:PooledByteBufAllocator实例维护的一个线程变量。
多种分类的MemoryRegionCache数组用作内存缓存,MemoryRegionCache内部是链表,队列里面存Chunk。
PoolChunk里面维护了内存引用,内存复用的做法就是把buf的memory指向chunk的memory。
PooledByteBufAllocator.ioBuffer运作过程梳理:
3 零拷贝机制
Netty的零拷贝机制,是一种应用层的实现。和底层JVM、操作系统内存机制并无过多关联。
- CompositeByteBuf,将多个ByteBuf合并为一个逻辑上的ByteBuf,避免了各个ByteBuf之间的拷贝
CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
ByteBuf newBuffer = compositeByteBuf.addComponents(true, buffer1, buffer2);
- wrapedBuffer()方法,将byte[]数组包装成ByteBuf对象。
ByteBuf newBuffer = Unpooled.wrappedBuffer(new byte[]{1,2,3,4,5});
- slice()方法,将一个ByteBuf对象切分成多个ByteBuf对象
ByteBuf buffer1 = Unpooled.wrappedBuffer("hello".getBytes());
ByteBuf newBuffer = buffer1.slice(1, 2);
使用ByteBuf是Netty高性能很重要的一个原因!
参考文章
结语
本人所有博客仅用于学习记录,不做任何商业用途,如涉及侵权,还请联系删除,感谢阅读,欢迎留言,一起进步~