本文分享内容如下
- AbstractByteBuf分析
- readXXX系列方法
- 读写方法分析
- ensureWritable分析
- capacity分析
- setBytes(int, byte[], int, int) 分析
- AbstractReferenceCountedByteBuf分析
- ByteBuffer-put系列方法分析
- UnpooledHeapByteBuf分析
- Head,Direct,UnsafeDirect 三种类型ByteBuf区别分析
- 内存池分配器分析
ByteBuf概览
主要类继承图如下
下面逐个进行分析
AbstractByteBuf分析
readXXX系列方法
//int 相当于4个byte大小,读取4个byte位,拼接成int
public int readInt() {
checkReadableBytes(4);
int v = _getInt(readerIndex);//将4位byte按照高低拼接。
readerIndex += 4;
return v;
}
同理 readShort 2个byte,readLong 8个byte。
读写方法分析
AbstractByteBuf中读写方法比较多,下面读写各分析一个典型的方法
//将当前的ByteBuf中从dstIndex开始长度为length的数据写入到sdt中,读取成功readerIndex增加length
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
checkReadableBytes(length);//简单的校验
getBytes(readerIndex, dst, dstIndex, length);//拷贝到src中
readerIndex += length;
return this;
}
将src中从srcIndex开始长度为length的数据写入到当前Buf中,写入成功writerIndex增加length
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
ensureWritable(length);
setBytes(writerIndex, src, srcIndex, length);//与readBytes中使用同一方法
writerIndex += length;
return this;
}
ensureWritable(length);在读写中都用到了,下面详细分析一下。
ensureWritable分析
public ByteBuf ensureWritable(int minWritableBytes) {
//各种check
// Normalize the current capacity to the power of 2.
//计算新容量
int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);
// Adjust to the new capacity.
capacity(newCapacity);//扩容或缩容量
return this;
}
private int calculateNewCapacity(int minNewCapacity) {
final int maxCapacity = this.maxCapacity;
final int threshold = 1048576 * 4; // 4 MiB page //大容量时 计划每次增长4MB
if (minNewCapacity == threshold) {
return threshold;
}
// If over threshold, do not double but just increase by threshold.
if (minNewCapacity > threshold) {// 新容量较大,进行大容量扩容
int newCapacity = minNewCapacity / threshold * threshold; //获取threshold整数倍的容量值
if (newCapacity > maxCapacity - threshold) {//应该增长threshold,但是最大容量不允许,新容量为最大容量
newCapacity = maxCapacity;
} else {//增长threshold
newCapacity += threshold;
}
return newCapacity;
}
//容较小,进行小容量扩容
int newCapacity = 64;
//取64*2N次幂 大于minNewCapacity 的最小值
// 如 minNewCapacity=255 newCapacity 最后等于 512
while (newCapacity < minNewCapacity) {
newCapacity <<= 1;
}
//防止newCapacity超出maxCapacity,默认 maxCapacity是Integer.MAX, 如果newCapacity超出maxCapacity,newCapacity至少是maxCapacity的1/2,应该在大容量扩容就被处理掉了,此时下面这个取最小值没有用。
return Math.min(newCapacity, maxCapacity);
}
capacity分析
capacity有不同的实现,下面举例分析,其他实现逻辑上相同,细节有按照其特性实现。
io.netty.buffer.UnpooledDirectByteBuf-capacity分析
public ByteBuf capacity(int newCapacity) {
ensureAccessible();
if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity);
}
int readerIndex = readerIndex();
int writerIndex = writerIndex();
int oldCapacity = capacity;
if (newCapacity > oldCapacity) {//扩容
ByteBuffer oldBuffer = buffer;
ByteBuffer newBuffer = allocateDirect(newCapacity);
oldBuffer.position(0).limit(oldBuffer.capacity());
newBuffer.position(0).limit(oldBuffer.capacity());
newBuffer.put(oldBuffer);//put的逻辑是将 src limit减去position 即src.remaining() 长度的byte拷贝到 newBuffer中,从position 开始。
//这里是将oldBuffer中的byte拷贝到newBuffer中去,扩容的同时也复制了数据
newBuffer.clear();
setByteBuffer(newBuffer);
} else if (newCapacity < oldCapacity) {//缩容量
ByteBuffer oldBuffer = buffer;
ByteBuffer newBuffer = allocateDirect(newCapacity);
if (readerIndex < newCapacity) {//当前写入索引小于新容量
if (writerIndex > newCapacity) { //readerIndex < newCapacity<writerIndex 只能截取 readerIndex ~newCapacity 的有效数据
writerIndex(writerIndex = newCapacity);
}
//当writerIndex < newCapacity==true,即readerIndex <writerIndex <newCapacity,不需要处理writerIndex
//拷贝oldBuffer有效数据到newBuffer
oldBuffer.position(readerIndex).limit(writerIndex);
newBuffer.position(readerIndex).limit(writerIndex);
newBuffer.put(oldBuffer);
newBuffer.clear();
} else {//这块不理解,感觉有问题
setIndex(newCapacity, newCapacity);
}
setByteBuffer(newBuffer);//设置核心依赖的ByteBuffer
}
return this;
}
setBytes(int, byte[], int, int) 分析
setBytes与capacity情况类似,下面举例分析。
UnpooledHeapByteBuf.setBytes(int, byte[], int, int) 分析
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);//检查 防止数组越界
System.arraycopy(src, srcIndex, array, index, length);//byte copy
return this;
}
使用arraycopy完成byte拷贝
到此 AbstractByteBuf的读写典型方法就分析完了
操作索引方法
这部分方法比较简单,不详细分析
public ByteBuf readerIndex(int readerIndex):设置读索引
public ByteBuf writerIndex(int writerIndex):设置写索引
还有mark,reset readerIndex和writerIndex方法。
@Override
public int maxWritableBytes() {
return maxCapacity() - writerIndex;
}
@Override
public ByteBuf markReaderIndex() {
markedReaderIndex = readerIndex;
return this;
}
@Override
public ByteBuf resetReaderIndex() {
readerIndex(markedReaderIndex);
return this;
}
@Override
public ByteBuf markWriterIndex() {
markedWriterIndex = writerIndex;
return this;
}
@Override
public ByteBuf resetWriterIndex() {
writerIndex = markedWriterIndex;
return this;
}
重用缓存方法分析
public ByteBuf discardReadBytes() {
ensureAccessible();
if (readerIndex == 0) {
return this;
}
if (readerIndex != writerIndex) {//数据被读取部分
setBytes(0, this, readerIndex, writerIndex - readerIndex);//未读数据前移
writerIndex -= readerIndex;
adjustMarkers(readerIndex);//调整mark值
readerIndex = 0;
} else {//数据全部读取
adjustMarkers(readerIndex);
writerIndex = readerIndex = 0;
}
return this;
}
//跳过length个byte数据, readerIndex+=length
public ByteBuf skipBytes(int length) {
checkReadableBytes(length);
int newReaderIndex = readerIndex + length;
if (newReaderIndex > writerIndex) {//新的readerIndex不能超过writerIndex
throw new IndexOutOfBoundsException(String.format(
"length: %d (expected: readerIndex(%d) + length <= writerIndex(%d))",
length, readerIndex, writerIndex));
}
readerIndex = newReaderIndex;
return this;
}
AbstractReferenceCountedByteBuf分析
都是维护引用值的方法
引用值加1
public ByteBuf retain() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalReferenceCountException(0, 1);
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalReferenceCountException(Integer.MAX_VALUE, 1);
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) {
break;
}
}
return this;
}
引用值加increment
public ByteBuf retain(int increment) {
//...
}
引用值减1
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalReferenceCountException(0, -1);
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) {
if (refCnt == 1) {
deallocate();
return true;
}
return false;
}
}
}
引用值减decrement
public final boolean release(int decrement) {
//...
}
小结:AbstractReferenceCountedByteBuf中实现维护引用值得的多个方法
ByteBuffer-put系列方法分析
ByteBuf最终的实现类大量用到了ByteBuffer-put系列方法,了解其用法是很重要的。
注意:除了指定了写入位置的方法,下面分析的方法都从当前ByteBuffe的position 开始,。
将 src的 limit减去position 即src.remaining() 长度的byte拷贝到 当前ByteBuffer 中。
public ByteBuffer put(ByteBuffer src);
将src从offset开始length长度的byte拷贝到 当前ByteBuffer 中。
public ByteBuffer put(byte[] src, int offset, int length)
写入一个byte b值到 当前ByteBuffer 中。
public ByteBuffer put(byte b);
写入一个char b值到 当前ByteBuffer 中,char 类型2个byte大小,value值被拆成高低2个byte。
public ByteBuffer putChar(char value);
由于int 4个byte,short 2个byte,long 8个byte, float4个byte,double,long 8个byte
还有public ByteBuffer putXXX(char value);方法与putChar方法同理
在指定的位置写入value值
public abstract ByteBuffer putChar(int index, char value);
与putChar(char value)相同,还有 puttXXX(int index, char value);
UnpooledHeapByteBuf分析
getBytes系列方法
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
ensureAccessible();
dst.put(array, index, Math.min(capacity() - index, dst.remaining()));
return this;
}
getBytes是将数据写入指定目标,这个指定目标可以是 ByteBuf,byte[],ByteBuffer,OutputStream,GatheringByteChannel类型
UnpooledHeapByteBuf中只有一个readBytes方法,用于从当前buf中读出指定长度写到channel中去。
public int readBytes(GatheringByteChannel out, int length) throws IOException {
checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, length, true);
readerIndex += readBytes;
return readBytes;
}
setBytes系列方法
与getBytes相对应的是setBytes系列方法,是将指定目标数据写入写入当前buf,这个指定目标可以是 ByteBuf,byte[],ByteBuffer,OutputStream,GatheringByteChannel类型
获取基本类型的拼接方法 如
protected int _getInt(int index) {
return (array[index] & 0xff) << 24 |
(array[index + 1] & 0xff) << 16 |
(array[index + 2] & 0xff) << 8 |
array[index + 3] & 0xff;
}
截取一段创建新的ByteBuf
public ByteBuf copy(int index, int length) {
checkIndex(index, length);
byte[] copiedArray = new byte[length];
System.arraycopy(array, index, copiedArray, 0, length);
return new UnpooledHeapByteBuf(alloc(), copiedArray, maxCapacity());
}
//将ByteBuf 转换成ByteBuffer
private ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) {//use array new HeapByteBuffer
this.tmpNioBuf = tmpNioBuf = ByteBuffer.wrap(array);
}
return tmpNioBuf;
}
@Override
public ByteBuf copy(int index, int length) {
ensureAccessible();
ByteBuffer src;
try {
src = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
} catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
}
return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
}
ByteBuf pool, 创建工具类,辅助工具类。
Head,Direct,UnsafeDirect 三种类型ByteBuf区别分析
UnpooledHeadByteBuf
private UnpooledHeapByteBuf(
ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
super(maxCapacity);
//。。。
this.alloc = alloc;
setArray(initialArray);//数组
setIndex(readerIndex, writerIndex);
}
//内部数据使用byte[]维护
存数据典型方法:setBytes(int, byte[], int, int)
数组实现
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);
System.arraycopy(src, srcIndex, array, index, length);
return this;
}
UnpooledDirectByteBuf
构造方法
protected UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
//...
this.alloc = alloc;
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));//new DirectByteBuffer(capacity)
}
//与UnpooledUnsafeDirectByteBuf相同, 内部数据使用DirectByteBuffer维护。
存数据典型方法:setBytes(int, byte[], int, int)
NIO DirectByteBuffer 实现
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index).limit(index + length);
tmpBuf.put(src, srcIndex, length);
return this;
}
UnpooledUnsafeDirectByteBuf
protected UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
//...
this.alloc = alloc;
setByteBuffer(allocateDirect(initialCapacity));//new DirectByteBuffer(capacity)
}
//内部数据使用DirectByteBuffer维护。
存数据典型方法:setBytes(int, byte[], int, int)
使用Unsafe直接操作内存实现。
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkIndex(index, length);
if (length != 0) {
PlatformDependent.copyMemory(src, srcIndex, addr(index), length);
}
return this;
}
static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
}
内存池分配器分析
常用的分配方法: AbstractByteBufAllocator.directBuffer(int, int)
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
validate(initialCapacity, maxCapacity);
return newDirectBuffer(initialCapacity, maxCapacity);
}
UnpooledByteBufAllocator的实现
//直接调用构造方法
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
ByteBuf buf;
if (PlatformDependent.hasUnsafe()) {
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
return toLeakAwareBuffer(buf);
}
PooledByteBufAllocator的实现
使用内存池
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena<ByteBuffer> directArena = cache.directArena;
ByteBuf buf;
if (directArena != null) {//通常会执行这里
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
} else {//执行 UnpooledByteBufAllocator的 newDirectBuffer逻辑
if (PlatformDependent.hasUnsafe()) {
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
}
return toLeakAwareBuffer(buf);
}