系列
Netty源码分析 - Bootstrap服务端
Netty源码分析 - Bootstrap客户端
netty源码分析 - ChannelHandler
netty源码分析 - EventLoop类关系
netty源码分析 - register分析
Netty源码分析 - NioEventLoop事件处理
netty源码分析 - accept过程分析
Netty源码分析 - ByteBuf
Netty源码分析 - 粘包和拆包问题
开篇
这篇文章的用于阐述下Netty当中ByteBuf的基本类型,以及一些对应的内部分配器,算作一片入门的文章,阅读起来较为简单。
Pooled 和 Unpooled
Pooled池化内存分配每次从预先分配好的一块内存取一段连续内存封装成ByteBuf提供给应用程序。
Unpooled非池化每次进行内存分配的时候调用系统API向操作系统申请一块内存。
Unsafe 和 非Unsafe
- Unsafe直接获取ByteBuf在JVM内存地址调用JDK的Unsafe进行读写操作,通过ByteBuf分配内存首地址和当前指针基于内存偏移地址获取值。
- 非Unsafe不依赖JDK的Unsafe对象,通过内存数组和索引获取值。
Heap和Direct
- Heap在堆上进行内存分配,分配内存需要被GC管理,无需手动释放内存,依赖底层byte数组,
- Direct调用JDK的API进行内存分配,分配内存不受JVM控制最终不会参与GC过程,需要手动释放内存避免造成内存无法释放,依赖DirectByteBuffer对象内存
ByteBuf类关系图
- PooledByteBuf情况下分为Heap和Direct两种。
- UnPooledByteBuf的buf同样分为Heap和Direct两种。
- CompositeByteBuf只有一种分类。
ByteBuf结构
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
public abstract class AbstractByteBuf extends ByteBuf {
int readerIndex;
int writerIndex;
private int markedReaderIndex;
private int markedWriterIndex;
private int maxCapacity;
}
- ByteBuf的数据结构如上图所示。
- int readerIndex; //读索引
- int writerIndex; //写索引
- private int markedReaderIndex;//标记读索引
- private int markedWriterIndex;//标记写索引
- private int maxCapacity;//缓冲区的最大容量
ByteBuf类依赖图
UnpooledHeapByteBuf
public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
private final ByteBufAllocator alloc;
byte[] array;
private ByteBuffer tmpNioBuf;
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
this(alloc, new byte[initialCapacity], 0, 0, maxCapacity);
}
private UnpooledHeapByteBuf(
ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
super(maxCapacity);
this.alloc = alloc;
setArray(initialArray);
setIndex(readerIndex, writerIndex);
}
private void setArray(byte[] initialArray) {
array = initialArray;
tmpNioBuf = null;
}
}
- UnpooledHeapByteBuf的内部存储结构是byte[] array数组。
UnpooledDirectByteBuf
public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
private final ByteBufAllocator alloc;
private ByteBuffer buffer;
private ByteBuffer tmpNioBuf;
private int capacity;
private boolean doNotFree;
protected UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
this.alloc = alloc;
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
}
private void setByteBuffer(ByteBuffer buffer) {
ByteBuffer oldBuffer = this.buffer;
if (oldBuffer != null) {
if (doNotFree) {
doNotFree = false;
} else {
freeDirect(oldBuffer);
}
}
this.buffer = buffer;
tmpNioBuf = null;
capacity = buffer.remaining();
}
}
- UnpooledDirectByteBuf的ByteBuffer通过JDK创建的直接内测,即通过ByteBuffer.allocateDirect(initialCapacity)进行创建。
PooledDirectByteBuf
PooledHeapByteBuf
CompositeByteBuf
public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable {
private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
private static final Iterator EMPTY_ITERATOR = Collections.emptyList().iterator();
private final ByteBufAllocator alloc;
private final boolean direct;
private final List components;
private final int maxNumComponents;
private boolean freed;
CompositeByteBuf(
ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf[] buffers, int offset, int len) {
super(Integer.MAX_VALUE);
this.alloc = alloc;
this.direct = direct;
this.maxNumComponents = maxNumComponents;
components = newList(maxNumComponents);
addComponents0(false, 0, buffers, offset, len);
// 是否需要进行扩容
consolidateIfNeeded();
setIndex(0, capacity());
}
// 添加ByteBuf到components当中
private int addComponent0(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
assert buffer != null;
boolean wasAdded = false;
try {
checkComponentIndex(cIndex);
int readableBytes = buffer.readableBytes();
// No need to consolidate - just add a component to the list.
@SuppressWarnings("deprecation")
Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice());
if (cIndex == components.size()) {
wasAdded = components.add(c);
if (cIndex == 0) {
// //如果是第一个buffer,则该Component的endOffset为buffer的大小。
c.endOffset = readableBytes;
} else {
// 如果不是第一个buffer,则该buffer的offset为上一个的end
Component prev = components.get(cIndex - 1);
c.offset = prev.endOffset;
// 如果不是第一个buffer,则该buffer的endOffset需要和之前的累加
c.endOffset = c.offset + readableBytes;
}
} else {
components.add(cIndex, c);
wasAdded = true;
if (readableBytes != 0) {
updateComponentOffsets(cIndex);
}
}
if (increaseWriterIndex) {
writerIndex(writerIndex() + buffer.readableBytes());
}
return cIndex;
} finally {
if (!wasAdded) {
buffer.release();
}
}
}
// 针对components判断是否需要进行扩容
private void consolidateIfNeeded() {
final int numComponents = components.size();
if (numComponents > maxNumComponents) {
final int capacity = components.get(numComponents - 1).endOffset;
ByteBuf consolidated = allocBuffer(capacity);
// We're not using foreach to avoid creating an iterator.
for (int i = 0; i < numComponents; i ++) {
Component c = components.get(i);
ByteBuf b = c.buf;
consolidated.writeBytes(b);
c.freeIfNecessary();
}
Component c = new Component(consolidated);
c.endOffset = c.length;
components.clear();
components.add(c);
}
}
}
CompositeByteBuf 在聚合时使用,多个buffer合并时,不需要copy,通过
CompositeByteBuf 可以把需要合并的bytebuf 组合起来,对外提供统一的readindex和writerindexCompositeByteBuf 里面有个ComponentList,继承ArrayList,聚合的bytebuf都放在ComponentList里面,最小容量为16。
CompositeByteBuf 在增加新的bytebuf后,会检查CompositeByteBuf的数组components 大小,默认大小是16,即在组合了16个bytebuf后,就要扩容了。
CompositeByteBuf是创建一个新的bytebuf,把数组里的16个bytebuf所有数据写到这个新创建bytebuf里,然后把旧数组清空,并把新创建的一个大的bytebuf添加到数组里。
内存分配器
UnpooledByteBufAllocator
public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
: new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
ByteBuf buf = PlatformDependent.hasUnsafe() ?
UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
}
public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) {
CompositeByteBuf buf = new CompositeByteBuf(this, false, maxNumComponents);
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
}
public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) {
CompositeByteBuf buf = new CompositeByteBuf(this, true, maxNumComponents);
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
}
}
- UnpooledByteBufAllocator提供newHeapBuffer、newDirectBuffer、compositeHeapBuffer等方法创建对应的ByteBuf对象。
PooledByteBufAllocator
public class PooledByteBufAllocator extends AbstractByteBufAllocator {
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena heapArena = cache.heapArena;
ByteBuf buf;
if (heapArena != null) {
buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
} else {
buf = new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
return toLeakAwareBuffer(buf);
}
@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena directArena = cache.directArena;
ByteBuf buf;
if (directArena != null) {
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
} else {
if (PlatformDependent.hasUnsafe()) {
buf = UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
}
return toLeakAwareBuffer(buf);
}
}
- PooledByteBufAllocator的newHeapBuffer、newDirectBuffer等方法创建对应的ByteBuf对象。
参考
- Netty之ByteBuf深入分析
- 对于 Netty ByteBuf 的零拷贝(Zero Copy) 的理解