PoolArena的allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) 方法
private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) { final int normCapacity = normalizeCapacity(reqCapacity); if (isTinyOrSmall(normCapacity)) { // capacity < pageSize int tableIdx; PoolSubpage<T>[] table; boolean tiny = isTiny(normCapacity); if (tiny) { // < 512 if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) { // was able to allocate out of the cache so move on return; } tableIdx = tinyIdx(normCapacity); table = tinySubpagePools; } else { if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) { // was able to allocate out of the cache so move on return; } tableIdx = smallIdx(normCapacity); table = smallSubpagePools; } final PoolSubpage<T> head = table[tableIdx]; /** * Synchronize on the head. This is needed as {@link PoolChunk#allocateSubpage(int)} and * {@link PoolChunk#free(long)} may modify the doubly linked list as well. */ synchronized (head) { final PoolSubpage<T> s = head.next; if (s != head) { assert s.doNotDestroy && s.elemSize == normCapacity; long handle = s.allocate(); assert handle >= 0; s.chunk.initBufWithSubpage(buf, null, handle, reqCapacity); incTinySmallAllocation(tiny); return; } } synchronized (this) { allocateNormal(buf, reqCapacity, normCapacity); } incTinySmallAllocation(tiny); return; } //普通型 <=16MB if (normCapacity <= chunkSize) { if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) { // was able to allocate out of the cache so move on return; } synchronized (this) { allocateNormal(buf, reqCapacity, normCapacity); ++allocationsNormal; } } else { // Huge allocations are never served via the cache so just call allocateHuge allocateHuge(buf, reqCapacity); } }
// Method must be called inside synchronized(this) { ... } block private void allocateNormal(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) { if (q050.allocate(buf, reqCapacity, normCapacity) || q025.allocate(buf, reqCapacity, normCapacity) || q000.allocate(buf, reqCapacity, normCapacity) || qInit.allocate(buf, reqCapacity, normCapacity) || q075.allocate(buf, reqCapacity, normCapacity)) { return; } // Add a new chunk. PoolChunk<T> c = newChunk(pageSize, maxOrder, pageShifts, chunkSize); boolean success = c.allocate(buf, reqCapacity, normCapacity); assert success; qInit.add(c); }
PoolChunk的allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity)方法
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) { final long handle; // >= pageSize的 if ((normCapacity & subpageOverflowMask) != 0) { // >= pageSize handle = allocateRun(normCapacity); } else { handle = allocateSubpage(normCapacity); } if (handle < 0) { return false; } ByteBuffer nioBuffer = cachedNioBuffers != null ? cachedNioBuffers.pollLast() : null; initBuf(buf, nioBuffer, handle, reqCapacity); return true; } private long allocateRun(int normCapacity) { //计算normCapacity应该在memoryMap中的哪一层 //因为叶子节点为8K也就是2 << 13 pageShifts=13 那么log2(normCapacity) - pageShifts就相当于除以8K int d = maxOrder - (log2(normCapacity) - pageShifts); //分配节点 int id = allocateNode(d); if (id < 0) { return id; } freeBytes -= runLength(id); return id; } //计算val是2的几次方,如val=2 则 log2(val)=1 private static int log2(int val) { // compute the (0-based, with lsb = 0) position of highest set bit i.e, log2 return INTEGER_SIZE_MINUS_ONE - Integer.numberOfLeadingZeros(val); }