netty源码分析11-ByteBuf

本文分享内容如下

  1. AbstractByteBuf分析
    1. readXXX系列方法
    2. 读写方法分析
    3. ensureWritable分析
    4. capacity分析
    5. setBytes(int, byte[], int, int) 分析
  2. AbstractReferenceCountedByteBuf分析
  3. ByteBuffer-put系列方法分析
  4. UnpooledHeapByteBuf分析
  5. Head,Direct,UnsafeDirect 三种类型ByteBuf区别分析
  6. 内存池分配器分析

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);

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章