Netty高效缓冲区ByteBuf
Netty 的ByteBuf定义了三个属性:写下标(writerIndex),读下标(readerIndex)、容量大小(capacity),ByteBuf的操作由三个属性完成。
- 超出capacity动态扩容
- 丰富的api
//1、创建非池化的ByteBuf 大小设置为10
ByteBuf byteBuf= Unpooled.buffer(10);
//原始ByteBuf*************>UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 10)
System.out.println("原始ByteBuf*************>"+byteBuf.toString());
//ByteBuf内容为**********>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf内容为**********>"+ Arrays.toString(byteBuf.array()));
//2 写入内容
byte[] bytes="Dawn".getBytes();
byteBuf.writeBytes(bytes);
//写入的bytes为*********>[68, 97, 119, 110]
System.out.println("写入的bytes为*********>"+Arrays.toString(bytes));
//写入内容后ByteBuf为*********>UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 4, cap: 10)
System.out.println("写入内容后ByteBuf为*********>"+byteBuf.toString());
//ByteBuf的内容为***********>[68, 97, 119, 110, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf的内容为***********>"+Arrays.toString(byteBuf.array()));
//3 读取内容
byte content1=byteBuf.readByte();
byte content2=byteBuf.readByte();
//读取的内容为:[68, 97]
System.out.println("读取的内容为:"+Arrays.toString(new byte[]{content1,content2}));
//读取内容后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 2, widx: 4, cap: 10)
System.out.println("读取内容后ByteBuf:"+byteBuf.toString());
//ByteBuf内容为[68, 97, 119, 110, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf内容为"+Arrays.toString(byteBuf.array()));
//4 将读取过的内容丢弃
byteBuf.discardReadBytes();
//将读取过的内容丢弃后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 10)
System.out.println("将读取过的内容丢弃后ByteBuf:"+byteBuf.toString());
//ByteBuf的内容为:[119, 110, 119, 110, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf的内容为:"+Arrays.toString(byteBuf.array()));
//5 清空读写指针
byteBuf.clear();
//将读写指针清空后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 10)
System.out.println("将读写指针清空后ByteBuf:"+byteBuf.toString());
//ByteBuf 的内容为:[119, 110, 119, 110, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf 的内容为:"+Arrays.toString(byteBuf.array()));
//6 写入内容
byte[] bytes1="On".getBytes();
byteBuf.writeBytes(bytes1);
//写入的bytes:[79, 110]
System.out.println("写入的bytes:"+Arrays.toString(bytes1));
//写入内容后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 10)
System.out.println("写入内容后ByteBuf:"+byteBuf.toString());
//ByteBuf的内容:[79, 110, 119, 110, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf的内容:"+Arrays.toString(byteBuf.array()));
// 7 将ByteBuf清零
byteBuf.setZero(0,byteBuf.capacity());
//内容清零后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 10)
System.out.println("内容清零后ByteBuf:"+byteBuf.toString());
//ByteBuf的内容:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf的内容:"+Arrays.toString(byteBuf.array()));
// 8 写入超过10容量大小的字符串,动态扩容
byte[] inputeContent="Come on,Dawn.".getBytes();
byteBuf.writeBytes(inputeContent);
//写入的bytes:[67, 111, 109, 101, 32, 111, 110, 44, 68, 97, 119, 110, 46]
System.out.println("写入的bytes:"+Arrays.toString(inputeContent));
//写入超过容量后的ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 15, cap: 64)
System.out.println("写入超过容量后的ByteBuf:"+byteBuf.toString());
//ByteBuf的内容:[0, 0, 67, 111, 109, 101, 32, 111, 110, 44, 68, 97, 119, 110, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
System.out.println("ByteBuf的内容:"+Arrays.toString(byteBuf.array()));
- 动态扩容实现原理
当写入数据超过定义ByteBuf的capacity时动态库容,每当想ByteBuf写入数据会计算最小所需容量minNewCapacity(writerIndex+写入的字符长度)。当超过默认阈值(threshold=4M)时,容量扩展逻辑为最新所需容量除阈值再剩阈值再加阈值;当最小所需容量小于阈值时,容量扩展逻辑为,默认值为64个字节,当最小容量小于64个字节,扩容到64字节。大于64字节时时候64*2的n次的库容。 - 动态扩容源码分析
// minNewCapacity为写下标值wrinterIndex+写入输入的字节长度,maxCapicty为Int类型最大的字节数
public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
if (minNewCapacity < 0) {
throw new IllegalArgumentException("minNewCapacity: " + minNewCapacity + " (expected: 0+)");
}
if (minNewCapacity > maxCapacity) {
throw new IllegalArgumentException(String.format(
"minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
minNewCapacity, maxCapacity));
}
//默认阈值为4M
final int threshold = CALCULATE_THRESHOLD; // 4 MiB page
if (minNewCapacity == threshold) {
return threshold;
}
// 所需最小容量大于阈值时
if (minNewCapacity > threshold) {
int newCapacity = minNewCapacity / threshold * threshold;
if (newCapacity > maxCapacity - threshold) {
newCapacity = maxCapacity;
} else {
newCapacity += threshold;
}
return newCapacity;
}
// // 所需最小容量小于阈值时,默认最小库容从64字节开始
int newCapacity = 64;
// 扩容规则:扩容值(库容值从64*2开始,扩容值=库容值*2)*2,直到扩容值大于或等于最小所需容量
while (newCapacity < minNewCapacity) {
newCapacity <<= 1;
}
return Math.min(newCapacity, maxCapacity);
}
Netty 零拷贝机制
- 零拷贝机制
// 改变byteBuf 具体某个的字节
byte[] arr={1,2,3,4,5,6};
// 包装数组,数组转为bytebuf缓存区
ByteBuf byteBuf = Unpooled.wrappedBuffer(arr);
System.out.println(byteBuf.getByte(5));
arr[5]= 7;
System.out.println(byteBuf.getByte(5));
// 拆包
ByteBuf sliceByteBuf = Unpooled.wrappedBuffer("Nothing is impossible".getBytes());
ByteBuf newByteBuf = sliceByteBuf.slice(0,7);
//如果该缓冲区是另一个缓冲区的包装器,则返回底层缓冲区实例
newByteBuf.unwrap();
System.out.println(newByteBuf.toString());
System.out.println(new String(new byte[]{newByteBuf.getByte(6)}));
// 容器大小7
System.out.println(newByteBuf.capacity());
//UnpooledSlicedByteBuf(ridx: 0, widx: 7, cap: 7/7, unwrapped: UnpooledHeapByteBuf(ridx: 0, widx: 21, cap: 21/21))
System.out.println(sliceByteBuf.toString());
//复合缓存区
ByteBuf byteBufOne = Unpooled.buffer(6);
byteBufOne.writeByte(3);
ByteBuf byteBufTwo = Unpooled.buffer(2);
byteBufTwo.writeByte(5);
//返回一个新的没有组件的big-endian复合缓冲区
CompositeByteBuf compositeByteBuf=Unpooled.compositeBuffer();
CompositeByteBuf newBuf=compositeByteBuf.addComponents(true,byteBufOne,byteBufTwo);
//CompositeByteBuf(ridx: 0, widx: 2, cap: 2, components=2)
System.out.println(newBuf);
职责链实现原理
职责链三大要素:抽象处理器,处理器上下文(维护处理器上下文及执行处理器),处理器具体实现
- 抽象处理器
abstract class AbstractHandler {
//handler 方法,处理器
abstract void doHanlder(HandlerChainContext handlerChainContext, Object object);
}
- Handler处理器上下文
public class HandlerChainContext {
// 下一个节点
HandlerChainContext next;
// 抽象处理方法
AbstractHandler abstactHandler;
// 构造函数 给handler赋值
public HandlerChainContext(AbstractHandler handler) {
this.abstactHandler = handler;
}
// 处理方法
void handler(Object obj){
this.abstactHandler.doHanlder(this,obj);
}
/*
* 执行下一个handler
* */
void runNext(Object object){
if(this.next!=null){
this.next.handler(object);
}
}
}
- 具体处理器实现
public class DawnHandler extends AbstractHandler {
@Override
void doHanlder(HandlerChainContext handlerChainContext, Object object) {
object=object.toString()+" Dawn handler ";
System.out.println(" Handler one:"+object);
// 执行下一个
handlerChainContext.runNext(object);
}
}
- 职责链实例
// 初始化时候构造一个head 作为责任链的开始 但并没有具体执行
public HandlerChainContext head= new HandlerChainContext(new AbstractHandler() {
@Override
void doHanlder(HandlerChainContext handlerChainContext, Object object) {
handlerChainContext.runNext(object);
}
});
// 从头节点开始请求执行
public void requestProcess(Object object){
this.head.handler(object);
}
// 在职责链尾部新增处理器
public void addLast(AbstractHandler handler){
HandlerChainContext context=head;
// 保证context为最后一个节点
while (context.next!=null){
context=context.next;
}
context.next=new HandlerChainContext(handler);
}
public static void main(String[] args) {
//构建职责链
DawnPipeline dawnPipeline=new DawnPipeline();
dawnPipeline.addLast(new DawnHandler());
dawnPipeline.addLast(new StarHandler());
dawnPipeline.addLast(new DawnHandler());
dawnPipeline.addLast(new StarHandler());
dawnPipeline.addLast(new DawnHandler());
// 执行职责链
dawnPipeline.requestProcess("Come on,Dawn!");
}
总结
本文介绍了Netty的高效的ByteBuf 基本使用、动态库容原理,通过零拷贝机制的示例,职责链实现原理示例,可以初步理解什么是netty的零拷贝机制及职责链的使用。