1 初始ByteBuf
ByteBuf是Netty整个结构中最为底层的模块,主要负责把数据从底层I/O读取到ByteBuf,然后传递给应用程序,应用程序处理完成后再把数据封装成ByteBuf写回I/O。所以,ByteBuf是直接与底层打交道的一层抽象。
2 ByteBuf的基本结构
Netty官方对ByteBuf的描述,具体如下:
从上面ByteBuf的结构来看,发现ByteBuf有三个非常重要的指针,分别是readerIndex(记录读指针的开始位置)、writerIndex(记录写指针的开始位置)和capacity(缓冲区的总长度),三者的关系是:readerIndex <= writerIndex <= capacity。从0到readerIndex为discardable bytes,表示是无效的;从readerIndex 到 writerIndex 为readable bytes,表示可读数据区;从writerIndex 到capacity位writable bytes,表示这段区间空闲,可以往里面写数据。除了这三个指针,ByteBuf里面其实还有一个指针maxCapacity,它相当于ByteBuf扩容的最大阈值,相应代码如下。
/*** Returns the maximum allowed capacity of this buffer. If a user attempts to increase the* capacity of this buffer beyond the maximum capacity using {@link #capacity(int)} or* {@link #ensureWritable(int)}, those methods will raise an* {@link IllegalArgumentException}.*/public abstract int maxCapacity();
这个maxCapacity指针可以看作是指向capacity之后的这段区间,Netty发现writable bytes写数据超出空间大小时,ByteBuf会提前自动扩容,扩容之后,就有了足够的空间来写数据,同时capacity也会同步更新,maxCapacity就是扩容后capacity的最大值。
3 ByteBuf的重要API
看一下ByteBuf的基本API,主要包括read() write() set() mark() reset()等方法。请看下表
在Netty中,ByteBuf大部分功能是在AbstractByteBuf中实现的。
public abstract class AbstractByteBuf extends ByteBuf {//读指针int readerIndex;//写指针int writerIndex;//mark之后的读指针private int markedReaderIndex;//mark之后的写指针private int markedWriterIndex;//最大容量private int maxCapacity;...
}
下面来看基本读写的骨架代码实现。例如,几个基本的判断读写区间的API,具体实现代码如下:
public abstract class AbstractByteBuf extends ByteBuf {
@Overridepublic boolean isReadable() {return writerIndex > readerIndex;}@Overridepublic boolean isReadable(int numBytes) {return writerIndex - readerIndex >= numBytes;}@Overridepublic boolean isWritable() {return capacity() > writerIndex;}@Overridepublic boolean isWritable(int numBytes) {return capacity() - writerIndex >= numBytes;}@Overridepublic int readableBytes() {return writerIndex - readerIndex;}@Overridepublic int writableBytes() {return capacity() - writerIndex;}@Overridepublic int maxWritableBytes() {return maxCapacity() - writerIndex;}@Overridepublic ByteBuf markReaderIndex() {markedReaderIndex = readerIndex;return this;}@Overridepublic ByteBuf resetReaderIndex() {readerIndex(markedReaderIndex);return this;}@Overridepublic ByteBuf markWriterIndex() {markedWriterIndex = writerIndex;return this;}@Overridepublic ByteBuf resetWriterIndex() {writerIndex = markedWriterIndex;return this;}
}
4 ByteBuf基本分类
AbstractByteBuf有很多子类,大致可以从三个维度进行分类。
1、Pooled:池化内存,就是从预先分配好的内存空间中提取一段连续内存封装成一个ByteBuf,分给应用程序使用。
2、Unsafe:是JDK底层的一个负责I/O操作的对象,可以直接获得对应的内存地址,基于内存地址进行读写操作。
3、Direct:堆外内存,直接调用JDK底层API进行物理内存分配,不在JVM的堆内存中,需要手动释放。
综上所述,其实ByteBuf会有6种组合:Pooled(池化内存)和Unpooled(非池化内存);Unsafe和非Unsafe;Heap(堆内存)和Direct(堆外内存)。下图是ByteBuf最重要的继承关系类结构图,通过命名就能一目了然。
ByteBuf最基本的读写API操作在AbstractByteBuf中已经实现了,其众多子类采用不同的策略来分配内存空间,下表是对重要的几个子类的总结。
5 ByteBufAllocator内存管理器
Netty中内存分配有一个顶层的抽象就是ByteBufAllocator,负责分配所有ByteBuf类型的内存。主要有几个重要的API,如下表:
以上API中为什么没有前面提到的8种类型的内存分配API?下面来看ByteBufAllocator的基本实现类AbstractByteBufAllocator,重点分析主要API的基本实现,比如buffer()方法的代码如下:
public abstract class AbstractByteBufAllocator implements ByteBufAllocator {public ByteBuf buffer() {if (directByDefault) {return directBuffer();}return heapBuffer();}
}
发现buffer方法中对是否默认支持directBuffer做了判断,如果支持则分配directBuffer,否则分配heapBuffer。
下面分别来看directBuffer方法和heapBuffer方法的实现,先来看directBuffer方法的代码。
@Overridepublic ByteBuf directBuffer() {return directBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE);}@Overridepublic ByteBuf directBuffer(int initialCapacity) {return directBuffer(initialCapacity, Integer.MAX_VALUE);}@Overridepublic ByteBuf directBuffer(int initialCapacity, int maxCapacity) {if (initialCapacity == 0 && maxCapacity == 0) {return emptyBuf;}validate(initialCapacity, maxCapacity);return newDirectBuffer(initialCapacity, maxCapacity);}
directBuffer方法有多个重载方法,最终会调用newDirectBuffer方法,下面看newDirectBuffer的代码。
protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);
发现newDirectBuffer方法其实是一个抽象方法,最终,交给AbstractByteBufAllocator的子类来实现。同理再来看heapBuffer方法的代码。
@Overridepublic ByteBuf heapBuffer() {return heapBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE);}@Overridepublic ByteBuf heapBuffer(int initialCapacity) {return heapBuffer(initialCapacity, Integer.MAX_VALUE);}@Overridepublic ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {if (initialCapacity == 0 && maxCapacity == 0) {return emptyBuf;}validate(initialCapacity, maxCapacity);return newHeapBuffer(initialCapacity, maxCapacity);}
发现heapBuffer方法最终是调用newHeapBuffer方法,而newHeapBuffer方法也是抽象方法,具体交给AbstractByteBufAllocator的子类实现。AbstractByteBufAllocator的子类主要有两个:PooledByteBufAllocator和UnpooledByteBufAllocator。AbstractByteBufAllocator的子类实现的类结构图如下:
分析到这里,已经知道directBuffer,heapBuffer和Pooled和Unpooled的分配规则,那么Unsafe和非Unsafe是如何判别的呢?其实是Netty自动判别的。如果操作系统底层支持Unsafe那就采用Unsafe读写,否则采用非Unsafe读写。可以从UnpooledByteBufAllocator的源码中验证,代码如下:
public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {@Overrideprotected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity): new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);}@Overrideprotected 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);}
}
发现在newHeapBuffer方法和newDirectBuffer方法中,分配内存判断PlatformDependent是否支持Unsafe,如果支持则创建Unsafe类型的Buffer,否则创建非Unsafe类型的Buffer,由Netty自动判断。