好的!Recycler 是 Netty 的轻量级对象池实现,我详细讲解它的原理。
Recycler 类的核心结构
public abstract class Recycler<T> {
// 线程本地的对象栈
private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {
@Override
protected Stack<T> initialValue() {
return new Stack<T>(Recycler.this, Thread.currentThread(), maxCapacityPerThread,
maxSharedCapacityFactor, ratioMask, maxDelayedQueuesPerThread);
}
};
// 每个线程最多缓存多少个对象
private final int maxCapacityPerThread;
// 其他配置参数
private final int maxSharedCapacityFactor;
private final int ratioMask;
private final int maxDelayedQueuesPerThread;
// 抽象方法,由子类实现,用于创建新对象
protected abstract T newObject(Handle<T> handle);
}
一、核心概念
1. Handle(句柄)
public interface Handle<T> {
void recycle(T object);
}
Handle 的作用:
- 每个对象都有一个 Handle
- Handle 记录对象属于哪个 Stack
- 通过 Handle 可以将对象归还到对象池
DefaultHandle 实现:
static final class DefaultHandle<T> implements Handle<T> {
private int lastRecycledId;
private int recycleId;
boolean hasBeenRecycled;
private Stack<?> stack;
private Object value; // 实际的对象
DefaultHandle(Stack<?> stack) {
this.stack = stack;
}
@Override
public void recycle(Object object) {
if (object != value) {
throw new IllegalArgumentException("object does not belong to handle");
}
Stack<?> stack = this.stack;
if (lastRecycledId != recycleId || stack == null) {
throw new IllegalStateException("recycled already");
}
stack.push(this); // 归还到栈
}
}
2. Stack(对象栈)
static final class Stack<T> {
final Recycler<T> parent;
final Thread thread;
// 存储对象的数组
DefaultHandle<?>[] elements;
// 栈顶指针
int size;
// 最大容量
private final int maxCapacity;
// 其他线程归还的对象队列
private volatile WeakOrderQueue head;
Stack(Recycler<T> parent, Thread thread, int maxCapacity, ...) {
this.parent = parent;
this.thread = thread;
this.maxCapacity = maxCapacity;
// 初始化数组
elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)];
}
}
Stack 的结构:
Stack:
elements = [Handle1, Handle2, Handle3, null, null, ...]
↑ ↑ ↑
size = 3
maxCapacity = 4096(默认)
二、get() 方法详解
public final T get() {
if (maxCapacityPerThread == 0) {
// 不使用对象池,直接创建
return newObject((Handle<T>) NOOP_HANDLE);
}
// 获取当前线程的 Stack
Stack<T> stack = threadLocal.get();
// 从栈中弹出一个 Handle
DefaultHandle<T> handle = stack.pop();
if (handle == null) {
// 栈为空,创建新对象
handle = stack.newHandle();
handle.value = newObject(handle);
}
return (T) handle.value;
}
步骤1:获取 Stack
Stack<T> stack = threadLocal.get();
第一次调用时:
- 触发
initialValue() - 创建新的 Stack
- 绑定到当前线程
后续调用:
- 直接返回已创建的 Stack
步骤2:从 Stack 弹出对象
DefaultHandle<T> handle = stack.pop();
Stack.pop() 方法:
DefaultHandle<T> pop() {
int size = this.size;
if (size == 0) {
// 栈为空,尝试从其他线程的队列获取
if (!scavenge()) {
return null;
}
size = this.size;
}
// 弹出栈顶元素
size --;
DefaultHandle ret = elements[size];
elements[size] = null;
if (ret.lastRecycledId != ret.recycleId) {
throw new IllegalStateException("recycled multiple times");
}
ret.recycleId = 0;
ret.lastRecycledId = 0;
this.size = size;
return ret;
}
执行过程:
假设 Stack 状态:
elements = [Handle1, Handle2, Handle3, null, ...]
size = 3
执行 pop():
1. size = 3,不为 0
2. size-- → size = 2
3. ret = elements[2] → Handle3
4. elements[2] = null
5. 重置 Handle3 的状态
6. this.size = 2
7. 返回 Handle3
结果:
elements = [Handle1, Handle2, null, null, ...]
size = 2
如果栈为空:
elements = [null, null, null, ...]
size = 0
执行 pop():
1. size == 0
2. scavenge() → 尝试从其他线程的队列获取
├─ 成功:size > 0,继续弹出
└─ 失败:返回 null
步骤3:创建新对象(如果需要)
if (handle == null) {
handle = stack.newHandle();
handle.value = newObject(handle);
}
stack.newHandle() 方法:
DefaultHandle<T> newHandle() {
return new DefaultHandle<T>(this);
}
newObject(handle) 方法:
这是抽象方法,由子类实现:
// PooledUnsafeDirectByteBuf 中的实现
private static final Recycler<PooledUnsafeDirectByteBuf> RECYCLER =
new Recycler<PooledUnsafeDirectByteBuf>() {
@Override
protected PooledUnsafeDirectByteBuf newObject(Handle<PooledUnsafeDirectByteBuf> handle) {
return new PooledUnsafeDirectByteBuf(handle, 0);
}
};
PooledUnsafeDirectByteBuf 构造函数:
PooledUnsafeDirectByteBuf(Handle<PooledUnsafeDirectByteBuf> recyclerHandle, int maxCapacity) {
super(recyclerHandle, maxCapacity);
}
// PooledByteBuf 构造函数
protected PooledByteBuf(Recycler.Handle<? extends PooledByteBuf<T>> recyclerHandle, int maxCapacity) {
super(maxCapacity);
this.recyclerHandle = (Handle<PooledByteBuf<T>>) recyclerHandle;
}
关键点:
- ByteBuf 保存了 recyclerHandle
- 后续可以通过 handle 归还对象
步骤4:返回对象
return (T) handle.value;
handle.value 就是实际的 ByteBuf 对象。
三、recycle() 方法详解(归还对象)
// 用户调用
buf.release();
// 最终调用
recyclerHandle.recycle(this);
Handle.recycle() 方法:
@Override
public void recycle(Object object) {
if (object != value) {
throw new IllegalArgumentException("object does not belong to handle");
}
Stack<?> stack = this.stack;
if (lastRecycledId != recycleId || stack == null) {
throw new IllegalStateException("recycled already");
}
stack.push(this);
}
Stack.push() 方法:
void push(DefaultHandle<?> item) {
Thread currentThread = Thread.currentThread();
if (thread == currentThread) {
// 同一个线程,直接压栈
pushNow(item);
} else {
// 不同线程,放入延迟队列
pushLater(item, currentThread);
}
}
private void pushNow(DefaultHandle<?> item) {
if ((item.recycleId | item.lastRecycledId) != 0) {
throw new IllegalStateException("recycled already");
}
item.recycleId = item.lastRecycledId = OWN_THREAD_ID;
int size = this.size;
if (size >= maxCapacity || dropHandle(item)) {
// 栈满了或者被丢弃
return;
}
if (size == elements.length) {
// 数组满了,扩容
elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
}
elements[size] = item;
this.size = size + 1;
}
执行过程:
假设 Stack 状态:
elements = [Handle1, Handle2, null, null, ...]
size = 2
执行 push(Handle3):
1. 检查是否同一个线程 ✓
2. pushNow(Handle3)
3. 设置 recycleId
4. size = 2 < maxCapacity ✓
5. size < elements.length ✓
6. elements[2] = Handle3
7. this.size = 3
结果:
elements = [Handle1, Handle2, Handle3, null, ...]
size = 3
四、完整的生命周期示例
第一次分配
// 1. 获取对象
PooledUnsafeDirectByteBuf buf = RECYCLER.get();
// 执行过程:
threadLocal.get() → Stack (第一次创建)
stack.pop() → null (栈为空)
stack.newHandle() → Handle1
newObject(Handle1) → new PooledUnsafeDirectByteBuf(Handle1, 0)
Handle1.value = buf
返回 buf
// Stack 状态:
elements = [null, null, ...]
size = 0
使用和释放
// 2. 使用 ByteBuf
buf.writeInt(123);
// 3. 释放
buf.release();
// 执行过程:
buf.deallocate()
recyclerHandle.recycle(this)
Handle1.recycle(buf)
stack.push(Handle1)
pushNow(Handle1)
elements[0] = Handle1
size = 1
// Stack 状态:
elements = [Handle1, null, ...]
size = 1
第二次分配
// 4. 再次获取对象
PooledUnsafeDirectByteBuf buf2 = RECYCLER.get();
// 执行过程:
threadLocal.get() → Stack (已存在)
stack.pop() → Handle1 (从栈中弹出)
buf.reuse(maxCapacity) → 重置状态
返回 buf (复用了第一次的对象)
// Stack 状态:
elements = [null, null, ...]
size = 0
// 注意:buf2 和 buf 是同一个对象!
第三次分配(栈为空)
// 5. 第三次获取
PooledUnsafeDirectByteBuf buf3 = RECYCLER.get();
// 执行过程:
stack.pop() → null (栈为空)
stack.newHandle() → Handle2
newObject(Handle2) → new PooledUnsafeDirectByteBuf(Handle2, 0)
返回新对象
// 创建了新对象
五、跨线程回收(重点)
场景:线程 A 分配,线程 B 释放
// 线程 A
PooledUnsafeDirectByteBuf buf = RECYCLER.get();
// 将 buf 传递给线程 B
// 线程 B
buf.release();
问题:
- buf 是从线程 A 的 Stack 获取的
- 但在线程 B 中释放
- 不能直接放回线程 A 的 Stack(线程不安全)
解决方案:WeakOrderQueue
void push(DefaultHandle<?> item) {
Thread currentThread = Thread.currentThread();
if (thread == currentThread) {
// 同一个线程,直接压栈
pushNow(item);
} else {
// 不同线程,放入延迟队列
pushLater(item, currentThread);
}
}
pushLater() 方法
private void pushLater(DefaultHandle<?> item, Thread thread) {
// 获取或创建 WeakOrderQueue
Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
WeakOrderQueue queue = delayedRecycled.get(this);
if (queue == null) {
// 创建新的队列
if (delayedRecycled.size() >= maxDelayedQueues) {
// 队列太多,丢弃
delayedRecycled.put(this, WeakOrderQueue.DUMMY);
return;
}
// 创建新队列并链接到 Stack
if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {
return;
}
delayedRecycled.put(this, queue);
} else if (queue == WeakOrderQueue.DUMMY) {
// 已经达到上限,丢弃
return;
}
// 将对象放入队列
queue.add(item);
}
WeakOrderQueue 的结构:
private static final class WeakOrderQueue {
// 链表节点
private static final class Link extends AtomicInteger {
private final DefaultHandle<?>[] elements = new DefaultHandle[LINK_CAPACITY];
private int readIndex;
private Link next;
}
private final WeakReference<Thread> owner; // 拥有这个队列的线程
private final int id;
private Link head, tail;
private WeakOrderQueue next; // 下一个队列
private final Stack<?> stack; // 目标 Stack
}
跨线程回收的结构:
线程 A 的 Stack:
elements = [Handle1, Handle2, ...]
size = 2
head → WeakOrderQueue (线程 B 的队列)
├─ Link1: [Handle3, Handle4, ...]
└─ Link2: [Handle5, Handle6, ...]
→ WeakOrderQueue (线程 C 的队列)
└─ Link1: [Handle7, Handle8, ...]
执行过程:
1. 线程 A 分配对象:
buf = RECYCLER.get()
从线程 A 的 Stack 获取
2. 线程 B 释放对象:
buf.release()
├─ 检测到不是同一个线程
├─ 获取线程 B 的 DELAYED_RECYCLED
├─ 查找或创建 WeakOrderQueue
└─ queue.add(handle)
└─ 放入线程 B 的队列
3. 线程 A 再次分配:
buf2 = RECYCLER.get()
├─ stack.pop()
├─ size == 0(栈为空)
├─ scavenge() → 从 WeakOrderQueue 转移对象
│ ├─ 遍历 head 链表
│ ├─ 从 WeakOrderQueue 读取对象
│ └─ 放入 elements 数组
├─ size > 0
└─ 弹出对象
scavenge() 方法
boolean scavenge() {
// 尝试从 WeakOrderQueue 转移对象到 Stack
if (scavengeSome()) {
return true;
}
// 重置游标,下次从头开始
prev = null;
cursor = head;
return false;
}
boolean scavengeSome() {
WeakOrderQueue prev;
WeakOrderQueue cursor = this.cursor;
if (cursor == null) {
prev = null;
cursor = head;
if (cursor == null) {
return false;
}
} else {
prev = this.prev;
}
boolean success = false;
do {
// 从 WeakOrderQueue 转移对象
if (cursor.transfer(this)) {
success = true;
break;
}
WeakOrderQueue next = cursor.next;
if (cursor.owner.get() == null) {
// 线程已经结束,移除这个队列
if (cursor.hasFinalData()) {
for (;;) {
if (cursor.transfer(this)) {
success = true;
} else {
break;
}
}
}
if (prev != null) {
prev.next = next;
}
} else {
prev = cursor;
}
cursor = next;
} while (cursor != null && !success);
this.prev = prev;
this.cursor = cursor;
return success;
}
transfer() 方法:
boolean transfer(Stack<?> dst) {
Link head = this.head;
if (head == null) {
return false;
}
// 从 Link 读取对象
if (head.readIndex == LINK_CAPACITY) {
if (head.next == null) {
return false;
}
this.head = head = head.next;
}
final int srcStart = head.readIndex;
int srcEnd = head.get();
final int srcSize = srcEnd - srcStart;
if (srcSize == 0) {
return false;
}
final int dstSize = dst.size;
final int expectedCapacity = dstSize + srcSize;
if (expectedCapacity > dst.elements.length) {
// 目标数组需要扩容
final int actualCapacity = dst.increaseCapacity(expectedCapacity);
srcEnd = min(srcStart + actualCapacity - dstSize, srcEnd);
}
if (srcStart != srcEnd) {
final DefaultHandle[] srcElems = head.elements;
final DefaultHandle[] dstElems = dst.elements;
int newDstSize = dstSize;
// 批量转移
for (int i = srcStart; i < srcEnd; i++) {
DefaultHandle element = srcElems[i];
if (element.recycleId == 0) {
element.recycleId = element.lastRecycledId;
} else if (element.recycleId != element.lastRecycledId) {
throw new IllegalStateException("recycled already");
}
srcElems[i] = null;
if (dst.dropHandle(element)) {
continue;
}
element.stack = dst;
dstElems[newDstSize++] = element;
}
if (srcEnd == LINK_CAPACITY && head.next != null) {
this.head = head.next;
}
head.readIndex = srcEnd;
if (dst.size == newDstSize) {
return false;
}
dst.size = newDstSize;
return true;
} else {
return false;
}
}
转移过程示例:
线程 A 的 Stack:
elements = [null, null, ...]
size = 0
head → WeakOrderQueue (线程 B)
└─ Link: [Handle1, Handle2, Handle3, ...]
执行 scavenge():
1. cursor = head (线程 B 的队列)
2. cursor.transfer(stack)
├─ 从 Link 读取 Handle1, Handle2, Handle3
├─ 放入 Stack.elements
└─ 返回 true
结果:
elements = [Handle1, Handle2, Handle3, null, ...]
size = 3
六、Recycler 的优势
1. 减少对象创建
传统方式:
for (int i = 0; i < 10000; i++) {
ByteBuf buf = new PooledUnsafeDirectByteBuf(...);
// 使用
// 等待 GC
}
创建 10000 个对象
Recycler 方式:
for (int i = 0; i < 10000; i++) {
ByteBuf buf = RECYCLER.get();
// 使用
buf.release(); // 归还
}
可能只创建几十个对象,其他都是复用
2. 减少 GC 压力
对象复用:
- 不需要频繁创建对象
- 不需要频繁回收对象
- GC 压力大幅降低
3. 线程本地优化
每个线程有自己的 Stack:
- 无锁访问
- 性能极高
- 缓存友好
4. 支持跨线程回收
通过 WeakOrderQueue:
- 线程 A 分配的对象
- 可以在线程 B 释放
- 最终回到线程 A 的 Stack
- 保证线程安全
总结
Recycler 的核心机制:
- 线程本地 Stack:每个线程维护一个对象栈
- Handle 包装:每个对象都有一个 Handle,记录归属
- 同线程回收:直接压栈,无锁操作
- 跨线程回收:通过 WeakOrderQueue 延迟回收
- 懒加载转移:下次分配时才从 WeakOrderQueue 转移对象
与内存池的配合:
- Recycler 管理 ByteBuf 对象
- PoolArena 管理实际内存
- 两层池化,性能最优
现在理解 Recycler 了吗?
1360



被折叠的 条评论
为什么被折叠?



