先看其構造方法如下
// 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;
}
說明:上面主要分爲兩步,接下來會一個個簡析
// 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;
}