NOTE
ByteBufAllocator
ByteBufAllocator class hierarchy, AbstractByteBufAllocator, unpooled allocation, and pooled allocation
This is a historical learning note and may contain outdated or incomplete understanding.
ByteBufAllocator Class Hierarchy
A utility class for allocating memory.

ByteBufAllocator
The APIs here can only distinguish between heap and direct memory. The other two dimensions are implemented by the buffer method of AbstractByteBufAllocator.
buffer// used to allocate a buffer
ioBuffer// used to allocate a buffer suitable for I/O
heapBuffer// used to allocate a buffer on the heap
directBuffer// used to allocate a direct-memory buffer
// combine multiple buffers
compositeBuffer
compositeHeapBuffer
compositeDirectBuffer
AbstractByteBufAllocator
buffer Method
Look at its buffer method:
public ByteBuf buffer() {
// Allocate direct memory.
if (directByDefault) {
return directBuffer();
}
// Allocate heap memory.
return heapBuffer();
}
Allocate Direct Memory
public ByteBuf directBuffer() {
// Initial capacity and maximum capacity.
return directBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);
}
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
validate(initialCapacity, maxCapacity);
// Call the subclass method; it can be pooled or unpooled.
return newDirectBuffer(initialCapacity, maxCapacity);
}
Allocate Heap Memory
public ByteBuf heapBuffer() {
return heapBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);
}
public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
validate(initialCapacity, maxCapacity);
// Call the subclass method; it can be pooled or unpooled.
return newHeapBuffer(initialCapacity, maxCapacity);
}
UnpooledByteBufAllocator
newHeapBuffer
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
// Decide whether to use Unsafe to allocate memory according to whether Unsafe is available.
return PlatformDependent.hasUnsafe() ?
new InstrumentedUnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
new InstrumentedUnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
First look at InstrumentedUnpooledUnsafeHeapByteBuf, the version that uses Unsafe.
InstrumentedUnpooledUnsafeHeapByteBuf(UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
// UnpooledUnsafeHeapByteBuf
super(alloc, initialCapacity, maxCapacity);
}
UnpooledUnsafeHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
// UnpooledHeapByteBuf
super(alloc, initialCapacity, maxCapacity);
}
public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
checkNotNull(alloc, "alloc");
if (initialCapacity > maxCapacity) {
throw new IllegalArgumentException(String.format(
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
}
this.alloc = alloc;
// On the heap this is new byte[initialCapacity].
setArray(allocateArray(initialCapacity));
setIndex(0, 0);
}
newDirectBuffer
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
final ByteBuf buf;
// Decide whether to use Unsafe to allocate memory according to whether Unsafe is available.
if (PlatformDependent.hasUnsafe()) {
buf = noCleaner ? new InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(this, initialCapacity, maxCapacity) :
new InstrumentedUnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new InstrumentedUnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
}
With Unsafe
InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(
UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
// UnpooledUnsafeNoCleanerDirectByteBuf
super(alloc, initialCapacity, maxCapacity);
}
public UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
}
if (maxCapacity < 0) {
throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
}
if (initialCapacity > maxCapacity) {
throw new IllegalArgumentException(String.format(
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
}
this.alloc = alloc;
// direct uses ByteBuffer.allocateDirect(initialCapacity)
setByteBuffer(allocateDirect(initialCapacity), false);
}
final void setByteBuffer(ByteBuffer buffer, boolean tryFree) {
if (tryFree) {
ByteBuffer oldBuffer = this.buffer;
if (oldBuffer != null) {
if (doNotFree) {
doNotFree = false;
} else {
freeDirect(oldBuffer);
}
}
}
this.buffer = buffer;
// This is an important point. It ultimately uses UNSAFE.getLong(object, fieldOffset).
memoryAddress = PlatformDependent.directBufferAddress(buffer);
tmpNioBuf = null;
capacity = buffer.remaining();
}
Without Unsafe
InstrumentedUnpooledDirectByteBuf(
UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(alloc, initialCapacity, maxCapacity);
}
public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
}
if (maxCapacity < 0) {
throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
}
if (initialCapacity > maxCapacity) {
throw new IllegalArgumentException(String.format(
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
}
this.alloc = alloc;
// new DirectByteBuffer(capacity)
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
}
private void setByteBuffer(ByteBuffer buffer) {
ByteBuffer oldBuffer = this.buffer;
if (oldBuffer != null) {
if (doNotFree) {
doNotFree = false;
} else {
freeDirect(oldBuffer);
}
}
// Without Unsafe it simply stores the buffer.
this.buffer = buffer;
tmpNioBuf = null;
capacity = buffer.remaining();
}
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub