Netty源码-ByteBuffer扩容与缩容
AbstractNioByteChannel.read()
public final void read() {
final ChannelConfig config = config();
if (shouldBreakReadReady(config)) {
clearReadPending();
return;
}
final ChannelPipeline pipeline = pipeline();
final ByteBufAllocator allocator = config.getAllocator();
final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
allocHandle.reset(config);
ByteBuf byteBuf = null;
boolean close = false;
try {
do {
//创建ByteBuffer
byteBuf = allocHandle.allocate(allocator);
allocHandle.lastBytesRead(doReadBytes(byteBuf));
if (allocHandle.lastBytesRead() <= 0) {
// nothing was read. release the buffer.
byteBuf.release();
byteBuf = null;
close = allocHandle.lastBytesRead() < 0;
if (close) {
// There is nothing left to read as we received an EOF.
readPending = false;
}
break;
}
allocHandle.incMessagesRead(1);
readPending = false;
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
} while (allocHandle.continueReading());
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
if (close) {
closeOnRead(pipeline);
}
} catch (Throwable t) {
handleReadException(pipeline, byteBuf, t, close, allocHandle);
} finally {
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
}
byteBuf = allocHandle.allocate(allocator);如果数据量大就扩充,如果数据量小就缩容
1、这个方法决定了ByteBuf是直接内存还是堆内存
2、创建的ByteBuf是一个自适应的BufferBuf
一、Netty创建ByteBuf创建的是直接内存还是堆内存
DefaultMaxMessagesRecvByteBufAllocator.allocate(ByteBufAllocator alloc)
//ByteBuf的创建过程
public ByteBuf allocate(ByteBufAllocator alloc) {
//alloc.ioBuffer()是创建堆内存的ByteBuf还是直接内存的ByteBuf
//guess()对ByteBuf进行扩容与缩容
return alloc.ioBuffer(guess());
}
AbstractByteBufAllocator.ioBuffer()
public ByteBuf ioBuffer(int initialCapacity) {
//一般走if分支创建直接内存的
if (PlatformDependent.hasUnsafe() || isDirectBufferPooled()) {
return directBuffer(initialCapacity);
}
return heapBuffer(initialCapacity);
}
二、ByteBuf自适应决定ByteBuf的大小
AdaptiveRecvByteBufAllocator 自适应的核心
//扩容偏移量
private static final int INDEX_INCREMENT = 4;
//减容偏移量
private static final int INDEX_DECREMENT = 1;
//这是一个扩容池
static {
List<Integer> sizeTable = new ArrayList<Integer>();
for (int i = 16; i < 512; i += 16) {
// 16 32 48 64
sizeTable.add(i);
}
//当超过Interge的最大值这个循环结束
for (int i = 512; i > 0; i <<= 1) {//<<=1 表示乘以2
sizeTable.add(i);
}
SIZE_TABLE = new int[sizeTable.size()];
for (int i = 0; i < SIZE_TABLE.length; i ++) {
SIZE_TABLE[i] = sizeTable.get(i);
}
}
//查询容量池找索引 这个是采用二分查找算法从容量池进行查询
private static int getSizeTableIndex(final int size) {
for (int low = 0, high = SIZE_TABLE.length - 1;;) {
if (high < low) {
return low;
}
if (high == low) {
return high;
}
int mid = low + high >>> 1;
int a = SIZE_TABLE[mid];
int b = SIZE_TABLE[mid + 1];
if (size > b) {
low = mid + 1;
} else if (size < a) {
high = mid - 1;
} else if (size == a) {
return mid;
} else {
return mid + 1;
}
}
}
@Override
public int guess() {
//每一次结合我们接受的数据,猜测下一次ByteBuf的大小
return nextReceiveBufferSize;
}
public AdaptiveRecvByteBufAllocator(int minimum, int initial, int maximum) {
checkPositive(minimum, "minimum");
if (initial < minimum) {
throw new IllegalArgumentException("initial: " + initial);
}
if (maximum < initial) {
throw new IllegalArgumentException("maximum: " + maximum);
}
int minIndex = getSizeTableIndex(minimum);
if (SIZE_TABLE[minIndex] < minimum) {
this.minIndex = minIndex + 1;
} else {
this.minIndex = minIndex;
}
int maxIndex = getSizeTableIndex(maximum);
if (SIZE_TABLE[maxIndex] > maximum) {
this.maxIndex = maxIndex - 1;
} else {
this.maxIndex = maxIndex;
}
this.initial = initial;
}
扩容减容的实际
public void lastBytesRead(int bytes) {
//attemptedBytesRead() 表示ByteBuffer的大小
//bytes 表示这个写入的ByteBuf大小,如果相等,说明没有读完
//ByteBuf大小不够,需要进行扩容
if (bytes == attemptedBytesRead()) {
//扩容的核心
record(bytes);
}
super.lastBytesRead(bytes);
}
record(bytes);
//actualReadBytes表示实际读到的ByteBuf大小
private void record(int actualReadBytes) {
//INDEX_DECREMENT默认为1 index 表示的是1024的下标
//SIZE_TABLE[max(0, index - INDEX_DECREMENT)]表示的拿到512
if (actualReadBytes <= SIZE_TABLE[max(0, index - INDEX_DECREMENT)]) {
//默认decreaseNow为false
// 缩容的条件:是两次都不满足的话才缩容
if (decreaseNow) {
//保证缩容的最小值不能小于我们预设的ByteBuf的最小值
index = max(index - INDEX_DECREMENT, minIndex);
//通过下标取缩容的容量
nextReceiveBufferSize = SIZE_TABLE[index];
decreaseNow = false;
} else {
decreaseNow = true;
}
} else if (actualReadBytes >= nextReceiveBufferSize) {
//扩容的最大值不能大于我们预设的最大值
index = min(index + INDEX_INCREMENT, maxIndex);
///通过下标取扩容的容量
nextReceiveBufferSize = SIZE_TABLE[index];
decreaseNow = false;
}
二、Unsafe
主要负责read和write底层的实现
线程不安全----------------线程独享
IO操作
read NIOByteUnsafe
write AbstractUnsafe
Unsafe()的创建流程,在AbstractChannel