Netty Recycler源码解读

本文深入探讨了Netty框架中的Recycler对象缓存池机制,解析其内部实现原理,包括对象的创建、回收和获取流程,以及同线程与异线程回收的区别。

Recycler是一个轻量级的对象缓存池,用来实现对象的复用。下面是使用Recycler的一个简单实例:

import io.netty.util.Recycler;

public class RecycleTest {
    private static final Recycler<User> RECYCLER = new Recycler<User>() {
        //没有对象的时候,新建一个对象, 会传入一个handler,在Recycler池里,所有的对象都会转成DefaultHandle对象
        @Override
        protected User newObject(Handle<User> handle) {
            return new User(handle);
        }
    };

    private static class User {
        private final Recycler.Handle<User> handle;

        public User(Recycler.Handle<User> handle) {
            this.handle = handle;
        }

        public void recycle() {
            //通过handler进行对象的回收
            handle.recycle(this);
        }
    }

    public static void main(String[] args) {
        User user = RECYCLER.get();
        //直接调用user方法进行对象的回收
        user.recycle();

        User user1 = RECYCLER.get();
        //这里会返回true
        System.out.println(user1 == user);
    }
}

Recycler对象的创建

Recycler内部通过FastThreadLocal里的Stack栈来保存对象池,每次通过get方法从池中得到对象的时候,先通过FastThreadLocal得到Stack对象,具体的参数含义如下图所示:
5796101-e3dd62a715c8f9c7.png

Stack里通过数组存储着回收的对象,构造方法如下图:
5796101-9d118e3e57f354de.png
Stack的构造方法
对象的回收

Recycler对象的回收会调用stack的push方法将对象放入到栈里,这样就完成了对象的回收,具体逻辑如下:
5796101-bd8f7e4e31941e14.png

在push方法里,根据线程的不同,又可以分为同线程的回收,与异线程的回收。

同线程对象的回收

线程的回收相对比较简单,将对象放到Stack栈里就完成了对象的回收,代码如下:
5796101-932b0f61448c5db4.png

判断对象是否回收的逻辑:
5796101-13b730cb7cebc6b0.png
异线程对象的回收

异线程的回收是指创建对象的线程与调用recycler方法的线程不是同一个线程,这时候的回收逻辑就相对复杂了,里面用到了两个对象,分别为:

  • WeakOrderQueue 存储其它线程回收到本线程的对象,当某个线程从Stack中获取不到对象时会从WeakOrderQueue中获取对象。每个线程的Stack拥有1个WeakOrderQueue链表,链表每个节点对应1个其它线程的WeakOrderQueue,其它线程回收到该Stack的对象就存储在这个WeakOrderQueue里。
  • Link: WeakOrderQueue中包含1个Link链表,回收对象存储在链表某个Link节点里,当Link节点存储的回收对象满了时会新建1个Link放在Link链表尾,Link的容量为16
    对象结构如下图所示:
    5796101-c9dc9bb6c855d636.png

    具体的回收过程可以分为:
  • 获取WeakOrderQueue


    5796101-f65c5356159f4696.png
  • 如果没有相应的WeakOrderQueeu,则会创建WeakOrderQueue, 将创建线程的Stack与回收线程的WeakOrderQueue进行绑定,具体的代码如下:
    5796101-3ddfe7bcd60d47fe.png
    5796101-f31544c169d24fe4.png
  • 将对象追加到WeakOrderQueue


    5796101-c5d5ce94212567fc.png
  • WeakOrderQueue的构造方法如下:
    5796101-2be113d630056a36.png
  • Link构造方法
    5796101-3d6a22418a141266.png
获取一个对象

可以通过get方法从recycler对象里获取一个缓存的对象,下面是get方法的逻辑:
5796101-04706a87a21ef851.png
Recycler的get方法逻辑

Stack的pop方法
5796101-d9ef514c04f7f14f.png
从其它线程获取对象放到stack里
  • 从其它线程获取对象入口
    5796101-5d2e504697c02a25.png
  • 从其它线程攻取对象
    5796101-69d20abd9f22b169.png
    5796101-aa128e3459b11ea2.png
  • 将Link集合里的对象移到stack里,逻辑如下图:
    5796101-807392e1b7685031.png
    5796101-adae8890c348967a.png
### NettyRecycler 的使用方法 #### 创建与初始化 `Recycler` 是 Netty 提供的一个轻量级的对象池实现,用于减少频繁创建和销毁对象带来的性能开销。在 `Recycler` 内部维护了一个基于栈的数据结构 `Stack` 来存储可重用的对象实例[^2]。 ```java private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {}; ``` 这段代码展示了如何利用 `FastThreadLocal` 定义线程局部变量 `threadLocal`,从而使得每个线程都有自己独立的 `Stack` 实例,确保了操作的安全性和高效性。 #### 获取对象 当应用程序需要从 `Recycler` 中获取一个对象时,会调用相应的获取接口。如果当前线程对应的 `Stack` 不为空,则直接返回顶部的对象;否则将触发新的对象创建逻辑并将其加入到 `WeakOrderQueue` 队列中等待后续回收再利用[^3]。 ```java static WeakOrderQueue newQueue(Stack<?> stack, Thread thread) { WeakOrderQueue queue = new WeakOrderQueue(stack, thread); stack.setHead(queue); // 设置stack head属性 return queue; } ``` 此部分实现了队列节点之间的连接关系建立以及所有权标记等功能。 #### 回收对象 对于不再使用的对象应当及时归还给 `Recycler` 进行管理。这通常是在业务处理完成后显式地调用特定的方法完成。由于采用了弱引用机制 (`WeakReference`) 和合理的容量控制策略 (如设置最大共享容量),即使某些情况下未能成功释放资源也不会造成内存泄漏风险。 #### 常见问题解答 - **为什么选择使用 `Recycler`?** 主要是为了优化高频次短生命周期对象分配场景下的系统表现,降低GC压力的同时提高吞吐率。 - **是否会引发内存泄露?** 只要在设计上遵循最佳实践原则——即合理配置参数、适时清理无用强引用链路等措施,基本可以避免此类隐患的发生。 - **多线程环境下是否存在竞争条件?** 利用了 `FastThreadLocal` 技术特性保障各工作单元间互不干扰,因此不存在传统意义上的并发冲突现象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值