q100 = new PoolChunkList<T>(this, null, 100, Integer.MAX_VALUE, chunkSize); q075 = new PoolChunkList<T>(this, q100, 75, 100, chunkSize); q050 = new PoolChunkList<T>(this, q075, 50, 100, chunkSize); q025 = new PoolChunkList<T>(this, q050, 25, 75, chunkSize); q000 = new PoolChunkList<T>(this, q025, 1, 50, chunkSize); qInit = new PoolChunkList<T>(this, q000, Integer.MIN_VALUE, 25, chunkSize); q100.prevList(q075); q075.prevList(q050); q050.prevList(q025); q025.prevList(q000); q000.prevList(null); qInit.prevList(qInit);
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); }
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) { if (normCapacity > maxCapacity) { // Either this PoolChunkList is empty or the requested capacity is larger then the capacity which can // be handled by the PoolChunks that are contained in this PoolChunkList. return false; } for (PoolChunk<T> cur = head; cur != null; cur = cur.next) { if (cur.allocate(buf, reqCapacity, normCapacity)) { if (cur.usage() >= maxUsage) { remove(cur); nextList.add(cur); } return true; } } return false; }
@Override public int minUsage() { return minUsage0(minUsage); }
private void destroyPoolChunkLists(PoolChunkList<T>... chunkLists) { for (PoolChunkList<T> chunkList: chunkLists) { chunkList.destroy(this); } }
PoolChunkList(PoolArena<T> arena, PoolChunkList<T> nextList, int minUsage, int maxUsage, int chunkSize) { assert minUsage <= maxUsage; this.arena = arena; this.nextList = nextList; this.minUsage = minUsage; this.maxUsage = maxUsage; maxCapacity = calculateMaxCapacity(minUsage, chunkSize); }
/** * Moves the {@link PoolChunk} down the {@link PoolChunkList} linked-list so it will end up in the right * {@link PoolChunkList} that has the correct minUsage / maxUsage in respect to {@link PoolChunk#usage()}. */ private boolean move0(PoolChunk<T> chunk) { if (prevList == null) { // There is no previous PoolChunkList so return false which result in having the PoolChunk destroyed and // all memory associated with the PoolChunk will be released. assert chunk.usage() == 0; return false; } return prevList.move(chunk); }
void freeChunk(PoolChunk<T> chunk, long handle, SizeClass sizeClass, ByteBuffer nioBuffer) { final boolean destroyChunk; synchronized (this) { switch (sizeClass) { case Normal: ++deallocationsNormal; break; case Small: ++deallocationsSmall; break; case Tiny: ++deallocationsTiny; break; default: throw new Error(); } destroyChunk = !chunk.parent.free(chunk, handle, nioBuffer); } if (destroyChunk) { // destroyChunk not need to be called while holding the synchronized lock. destroyChunk(chunk); } }
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) { if (normCapacity > maxCapacity) { // Either this PoolChunkList is empty or the requested capacity is larger then the capacity which can // be handled by the PoolChunks that are contained in this PoolChunkList. return false; } for (PoolChunk<T> cur = head; cur != null; cur = cur.next) { if (cur.allocate(buf, reqCapacity, normCapacity)) { if (cur.usage() >= maxUsage) { remove(cur); nextList.add(cur); } return true; } } return false; }
/** * Calculates the maximum capacity of a buffer that will ever be possible to allocate out of the {@link PoolChunk}s * that belong to the {@link PoolChunkList} with the given {@code minUsage} and {@code maxUsage} settings. */ private static int calculateMaxCapacity(int minUsage, int chunkSize) { minUsage = minUsage0(minUsage); if (minUsage == 100) { // If the minUsage is 100 we can not allocate anything out of this list. return 0; } // Calculate the maximum amount of bytes that can be allocated from a PoolChunk in this PoolChunkList. // // As an example: // - If a PoolChunkList has minUsage == 25 we are allowed to allocate at most 75% of the chunkSize because // this is the maximum amount available in any PoolChunk in this PoolChunkList. return (int) (chunkSize * (100L - minUsage) / 100L); }
private void destroyPoolChunkLists(PoolChunkList<T>... chunkLists) { for (PoolChunkList<T> chunkList: chunkLists) { chunkList.destroy(this); } }
PoolChunkList(PoolArena<T> arena, PoolChunkList<T> nextList, int minUsage, int maxUsage, int chunkSize) { assert minUsage <= maxUsage; this.arena = arena; this.nextList = nextList; this.minUsage = minUsage; this.maxUsage = maxUsage; maxCapacity = calculateMaxCapacity(minUsage, chunkSize); }
/** * Moves the {@link PoolChunk} down the {@link PoolChunkList} linked-list so it will end up in the right * {@link PoolChunkList} that has the correct minUsage / maxUsage in respect to {@link PoolChunk#usage()}. */ private boolean move0(PoolChunk<T> chunk) { if (prevList == null) { // There is no previous PoolChunkList so return false which result in having the PoolChunk destroyed and // all memory associated with the PoolChunk will be released. assert chunk.usage() == 0; return false; } return prevList.move(chunk); }
void freeChunk(PoolChunk<T> chunk, long handle, SizeClass sizeClass, ByteBuffer nioBuffer) { final boolean destroyChunk; synchronized (this) { switch (sizeClass) { case Normal: ++deallocationsNormal; break; case Small: ++deallocationsSmall; break; case Tiny: ++deallocationsTiny; break; default: throw new Error(); } destroyChunk = !chunk.parent.free(chunk, handle, nioBuffer); } if (destroyChunk) { // destroyChunk not need to be called while holding the synchronized lock. destroyChunk(chunk); } }