Netty底层的策略
- Netty底层提供了扩容,涉及数据拷贝,可预测的缓冲区处理
- C语言的分配内存有Malloc实现
AdaptiveRecvByteBufAllocator
- AdaptiveRecvByteBufAllocator根据返回的大小会自动增或减可预测的Buffer,基于之前的读与写的对比的结构的调节大小
-
该RecvByteBufAllocator在反馈时自动增加和减少预测的缓冲区大小。
如果前面的读操作完全填满了分配的缓冲区,那么它将逐渐增加预期的可读字节数。如果read操作不能连续两次填充分配的缓冲区的一定数量,则会逐渐减少预期的可读字节数。否则,它将不断返回相同的预测。 -
RecvByteBufAllocator源码备注
//静态代码块的作用是对SIZE_TABLE数组填写1~38的坐标的值是16,32,48....一直到65536
//自动减少或者增加的幅度就是来自于这个数组。具体逻辑在HandleImpl对的record方法。
static {
List<Integer> sizeTable = new ArrayList<Integer>();
for (int i = 16; i < 512; i += 16) {
sizeTable.add(i);//1~16的设置是16到(512-16)
}
for (int i = 512; i > 0; i <<= 1) {
sizeTable.add(i);//从512到65536
}
SIZE_TABLE = new int[sizeTable.size()];
for (int i = 0; i < SIZE_TABLE.length; i ++) {
SIZE_TABLE[i] = sizeTable.get(i);//填写到SIZE_TABLE数组
}
}
//句柄实现
private final class HandleImpl extends MaxMessageHandle {
private final int minIndex;//最小索引
private final int maxIndex;//最大索引
private int index;//索引
private int nextReceiveBufferSize;//下一个接收缓存区的大小
private boolean decreaseNow;//减少的标识
public HandleImpl(int minIndex, int maxIndex, int initial) {
this.minIndex = minIndex;
this.maxIndex = maxIndex;
index = getSizeTableIndex(initial); //获取表里面的索引大小
nextReceiveBufferSize = SIZE_TABLE[index];
}
//预估处理接收值
@Override
public int guess() {
return nextReceiveBufferSize;
}
//处理记录实际的字节
private void record(int actualReadBytes) {
//判断实际读取字节与最大索引值
if (actualReadBytes <= SIZE_TABLE[Math.max(0, index - INDEX_DECREMENT - 1)]) {
if (decreaseNow) {
//获取最大索引
index = Math.max(index - INDEX_DECREMENT, minIndex);
nextReceiveBufferSize = SIZE_TABLE[index];//获取下一个接收缓存大小
decreaseNow = false;
} else {
decreaseNow = true;
}
} else if (actualReadBytes >= nextReceiveBufferSize) {
//获取最小索引
index = Math.min(index + INDEX_INCREMENT, maxIndex);
nextReceiveBufferSize = SIZE_TABLE[index];
decreaseNow = false;
}
}
//完成读写记录
@Override
public void readComplete() {
record(totalBytesRead());
}
}
HandleImpl
- HandleImpl类是继承MaxMessageHandle,然后跟踪到MaxMessageHandle,可以看出来此类有如下代码,这里只列部分。
public abstract class MaxMessageHandle implements ExtendedHandle {
private ChannelConfig config;//管道配置变量
private int maxMessagePerRead;//最大预期消息读变量
private int totalMessages;//总消息变量
private int totalBytesRead;//总读的总字节变量
private int attemptedBytesRead;//尝试去读的字节变量
private int lastBytesRead;//最后字节读变量
//不检测提供者尝试读取的字节
private final UncheckedBooleanSupplier defaultMaybeMoreSupplier = new UncheckedBooleanSupplier() {
@Override
public boolean get() {
return attemptedBytesRead == lastBytesRead;
}
};
/**
* 重置ChannelConfig 管道配置
*/
@Override
public void reset(ChannelConfig config) {
this.config = config;
maxMessagePerRead = maxMessagesPerRead();
totalMessages = totalBytesRead = 0;
}
//分配字节缓存器处理,此类比较重要
@Override
public ByteBuf allocate(ByteBufAllocator alloc) {
return alloc.ioBuffer(guess());
}
tedBytesRead = bytes;
}
//分配字节读
protected final int totalBytesRead() {
return totalBytesRead < 0 ? Integer.MAX_VALUE : totalBytesRead;
}
}
ByteBuf
- ByteBufAllocator
ByteBufAllocator展开里面的方法,可以看出来非常重要的一个类,里面包含
ioBuffer
(IO缓冲区),directBuffer
(直接缓冲区),heapBuffer
(堆缓冲区),compositeBuffer
(复合缓冲区),compositeDirectBuffer
(复合直接缓冲区)compositeHeapBuffer
(复合堆缓冲区),然后在展开的类的方法有一个calculateNewCapacity
方法,此方法尤为重要,计算ByteBuf的新容量,当ByteBuf需要以maxCapacity
为上限扩展minNewCapacity时使用该容量。
-
calculateNewCapacity
方法,由抽象AbstractByteBufAllocator和PreferHeapByteBufAllocator进行实现.
calculateNewCapacity
-
AbstractByteBufAllocator又由
PooledByteBufAllocator
和UnpooledByteBufAllocator
(池化的字节缓冲区分配器)(无池化的字节缓冲区分配器)进行底层的实现,
PooledByteBufAllocator UnpooledByteBufAllocatorPooledByteBufAllocator和UnpooledByteBufAllocator关系图
运算符
- << = 1 表示向左移一位 X 2 sizeTable分配可分配的大小Buffer
线程
- 线程本身不能运行,只能在程序上运行 一个Socket一个线程,线程开销大,主要是上下文切换的原因
值传递和引用传递
- 值传递是对基本类型变量而言的,传递的是该变量的一个副本改变副本不影响原来变量
- 引用传递一般是对对象类型变量而言,传递的是该对象地址的一个副本,并不是原对象本身
- 一般认为Java内的传递都是值传递,Java中实例对象的传递是引用传递
网友评论