ByteBuf是什么?
首先当前类是ByteBuf.java类,是netty缓存的抽象类。主要包含如下几个Index
0      <=      readerIndex   <=   writerIndex    <=    capacity
包含的方法大致如下
setXxx        //设置当前index对应的值
readXxx        //读
WriteXxx        //写
markXxx        //标记当前index
resetXxx        //reset到上面mark的index
其中AbstractByteBuf继承实现了某些具体的类,其继承关系如下:
 
Netty源码解析之ByteBuf简析
 
主要实现了ByteBuf的 读写、mark、reset等方法,详情不细说,有兴趣自己看。其中里面很多方法都仅做声明(模板方法模式),如
 
Netty源码解析之ByteBuf简析
 
继续往下跟可以发现如下结构图
 
Netty源码解析之ByteBuf简析
 
ByteBuf分为safe和unsafe方式取数据
  • safe方式:通过内存地址+偏移量 获取数据
  • unsafe方式:数组+下标   或    jdk底层byteBuf api拿数据
ByteBuf可分为Heap(堆内存)、Direct(直接内存),往下根据源码可知道
  • Heap中使用的是byte[]数据,Direct中使用的是直接内存(依赖JDK底层的DirectByteBuf,需要自己手动释放)
 

Netty内存管理器
当前内存管理的继承关系图如下(ByteBufAllocatr是最上层):
 
Netty源码解析之ByteBuf简析
 
 
接下来我们来看看UnpooledByteBufAllocator和PooledByteBufAllocator的实现和区别
1 均继承AbstractByteBufAllocator,但UnpooledByteBufAllocator更像是一个简化的内存分配器
 
Netty源码解析之ByteBuf简析
 
Netty源码解析之ByteBuf简析
 
 
2 先分析UnpooledByteBufAllocator,可发现其方法仅有6个如下截图(接下来大致分析一下):
 
Netty源码解析之ByteBuf简析
 
先看其构造方法如下
// UnpooledByteBufAllocator.java
public UnpooledByteBufAllocator(boolean preferDirect, boolean disableLeakDetector) {
    super(preferDirect);   //preferDirect用于决定是否使用directBuf
    this.disableLeakDetector = disableLeakDetector;
}
 
// AbstractByteBufAllocator.java
protected AbstractByteBufAllocator(boolean preferDirect) {
    // 需要两者都为true才标记为使用directBuf,即需要为unsafe
    directByDefault = preferDirect && PlatformDependent.hasUnsafe();
    emptyBuf = new EmptyByteBuf(this);
}
 
接下来看一下是如何分配的(从下面就可以判断当前方法都会判断是否safe,然后分别创建不同的buf)
// UnpooledByteBufAllocator.java
@Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
    return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) : new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
 
@Override
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);
}
 
3 上面简单的分析了Unpool的,接下来就不分析下Pool的(Pool的比较长,会单独出来讲解),注意的一点是Pool用的是
    private final PoolThreadLocalCache threadCache;
PoolThreadLocalCache继承了FastThreadLocal,是netty对ThreadLocal的一种优化,其主要优化了如下,可参见:https://www.jianshu.com/p/3fc2fbac4bb7 + https://blog.csdn.net/lirenzuo/article/details/94495469
    - 不使用jdk线性探测法的 Map,自定义了InternalThreadLocalMap,使用的是下标定位,所以更快,并且不会存在内存泄漏风险
 

下面继续讲解一下PoolByteBufAllocator.java中是如何分配内存的,其分配内存过程如下:
取一个实例化buffer的方法解析如下:
// PoolByteBufAllocator.java
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
    PoolThreadCache cache = threadCache.get();
     // 首先可看出heapArena是从cache中取出的,解析来我们可以看到分配的过程中涉及到了很多缓存
    PoolArena<byte[]> heapArena = cache.heapArena;
 
    ByteBuf buf;    
    if (heapArena != null) {
        buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
    } else {
        buf = new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
    }
 
    return toLeakAwareBuffer(buf);
}
 
上面我们主要解析PoolArena是如何处理的,跟踪heapArena.allocate()方法如下
// PoolArena.java
PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) {
    // 第一步:实例化一个buffer
    PooledByteBuf<T> buf = newByteBuf(maxCapacity);
    // 第二步:分配内存
    allocate(cache, buf, reqCapacity);
    return buf;
}
说明:上面主要分为两步,接下来会一个个简析
 
  • 第一步:实例化一个buffer(跟踪到如下)
// PooledUnsafeDirectByteBuf.java
static PooledUnsafeDirectByteBuf newInstance(int maxCapacity) {
    // 他是从回收的对象池(RECYCLER.get())中直接复用,而不会重新new一个
    PooledUnsafeDirectByteBuf buf = RECYCLER.get();
    buf.reuse(maxCapacity);
    return buf;
}
 
  • 第二步:分配内存
    • 分配内存这个会优先从缓存中进行分配(已使用并释放的),找一个差不多大小的缓存来分配掉,没有命中缓存才进行实际的内存分配。
// 以下的代码是优先找一个缓存进行分配的示例
if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) {
    // was able to allocate out of the cache so move on
    return;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

相关文章: