回答
在 Netty 中,对象池技术是 Netty 的性能优化技术,它是通过重用对象来减少对象创建和销毁的开销,从而提高应用程序的性能和 GC 的频率。
ByteBuf
是 Netty 中数据的载体,Netty 对它采用了对象池技术。ByteBuf
分为池化和非池化两种 ByteBuf
。其中池化的ByteBuf
可以重用内存空间,从而减少了内存分配和垃圾回收的压力。当请求一个新的ByteBuf
时,Netty会首先检查池中是否有可用的 ByteBuf
对象,如果有,则直接返回一个现成的对象;如果没有,则创建一个新对象并在使用后将其返回池中。
Netty的对象池技术主要依赖于Recycler
类。Recycler
在 Netty 中是一个轻量级的对象池,借助 Recycler
,Netty 可以完成对对象的重复使用。当 Netty 中的一个对象(如ByteBuf
)不再使用了,它可以被“回收”到Recycler
中,而不是被垃圾回收器回收。当需要一个新对象时,可以从Recycler
中获取一个已经存在的实例并重用它,而不是创建一个新的实例。
Recycler
的底层设计有点儿复杂,详细情况阅读下面的【扩展】部分。
扩展
Recycler 快速上手
对象池(英语:Object Pool Pattern)是一种设计模式。一个对象池包含一组已经初始化过且可以使用的对象,可以在有需求时创建和销毁对象。池的使用对象可以从池子中取得对象,对其进行操作处理,并在不需要时归还给池子而非直接销毁它。
Recycler 是 Netty 提供的自定义的轻量级的对象池,借助 Recycler 我们可以完成对 Java 对象的重复使用,下面大明哥就演示如何使用 Recycler。
@NoArgsConstructor
public class User {
private String name;
private Integer age;
private Recycler.Handle<User> handler;
public User(Recycler.Handle<User> handler) {
this.handler = handler;
}
public Recycler.Handle<User> getHandler() {
return handler;
}
}
public class RecyclerTest {
private static final Recycler<User> USER_RECYCLER = new Recycler<User>() {
@Override
protected User newObject(Handle<User> handle) {
// 新建对象
return new User(handle);
}
};
public static void main(String[] args) {
// 从对象池中获取对象
User user1 = USER_RECYCLER.get();
System.out.println(user1);
// 从对象池中获取对象
User user2 = USER_RECYCLER.get();
System.out.println(user2);
// 回收对象 user1
user1.getHandler().recycle(user1);
// 再次对象池中获取对象
User user3 = USER_RECYCLER.get();
System.out.println(user3);
System.out.println("user1 == user3:" + (user1 == user3));
}
}
在该实例中我们先从对象池中获取两个对象 user1、user2,由于这个时候 Recycler 中并没有对象,所以它会调用 Recycler 的 newObject()
创建一个新的 User 对象,然后我们再对对象 user1 进行回收,最后再从 Recycler 获取对象 user3,理论上来说 user1 == user3
,我们看运行结果:
com.sike.netty.jinjie.bytebuf.recycler.User@36f0f1be
com.sike.netty.jinjie.bytebuf.recycler.User@157632c9
com.sike.netty.jinjie.bytebuf.recycler.User@36f0f1be
user1 == user3:true
运行结果与我们预想的一模一样。
从上面示例我们可以看出,利用 Recycler 我们可以实现对象的回收和再利用。所以我们可以将其当做一个工具类在项目中使用,当然并不是所有场景都可以使用它,我们应该结合实际情况。一般来说符合如下条件,可以使用对象池:
- 对象创建开销大,且可以重复使用。我们要注意:并不是所有对象都可以重复利用的。
- 对象池的数量需要控制在可以接受的范围内,不能够无限膨胀。
复杂的老版本设计
我们先看 4.1.71
版本以前的设计,目前网上几乎所有 Recycler 的分析文章都是基于 4.1.71 之前的版本,所以大明哥先对之前的版本的设计做一个详细介绍,然后再介绍新版本,看看两者之间的实现差异。
我们先看它的内部结构图:
从图中可以看出它有三个核心组件:
- Stack
- DefaultHandle
- WeakOrderQueue
下面大明哥一一介绍这些组件。
- Stack