1.对象池技术介绍
对象池其实就是缓存一些对象从而避免大量创建同一个类型的对象, 类似线程池。对象池缓存了一些已经创建好的对象, 避免需要的时候创建。同时限制了实例的个数。
池化技术最终要的就是重复的使用池内已经创建的对象。
- 创建对象的开销大
- 会创建大量的实例
- 限制一些资源的使用
如果创建一个对象的开销特别大, 那么需要提前创建一些可以使用的并缓存起来, 池化技术就是重复使用对象, 提前创建并缓存起来重复使用就是池化, 可以降低创建对象的开销。
会大量创建实例的场景, 重复的使用对象可以减少创建的对象数量, 降低GC的压力。
对于限制资源的使用更多的是一种保护机制, 比如数据库连接池, 除去创建对象本身的开销, 们对外部系统也会造成压力, 比如大量创建链接对DB也是有压力的。那么池化除了可以优化资源外, 本身限制了资源数, 对外部系统也起到了一层保护作用。
2.如何实现对象池
Apache Commons Pool, Netty轻量级对象池的实现。
Apache Commons Pool开源软件库提供了一个对象池API和一系列对象池的实现, 支持各种配置, 比如活跃对象数或者闲置对象个数等。DBCP数据库连接池基于Apache Commons Pool实现。
Netty自己实现了一套轻量级的对象池, 在多个IO线程独立工作时候, 基于NioEventLoop的实现, 每个IO线程轮询单独的Selector实例来检索IO事件, 在IO来临时候开始处理。最常见的IO操作就是读写, 具体到NIO就是从内核缓冲区拷贝数据到用户缓冲区或者从用户缓冲区拷贝数据到内核缓冲区。
3.Netty对象池实现分析
NIO提供了两种Buffer最为缓冲区: DirectByteBuffer和HeapByteBuffer, Netty进行了池化提供性能。
Netty的池化分别为PooledDirectByteBuf 和PolledHeapByteBuf。
static PooledDirectByteBuf newInstance(int maxCapacity) {
PooledDirectByteBuf buf = RECYCLER.get();
buf.reuse(maxCapacity);
return buf;
}
可见RECYCLER是池化的核心, 通过RECYCLER.get获取一个实例。
Recycler就是Netty实轻量级池化技术的核心。
public class RecycleTest {
private static final Recycler<User> RECYCLER = new Recycler<User>(){
@Override
protected User newObject(Handle<User> handle) {
return new User(handle);
}
};
public static class User{
private final Recycler.Handle<User> handle;
public User(Recycler.Handle<User> handle){
this.handle = handle;
}
public void recycle(){
handle.recycle(this);
}
}
public static void main(String[] args) {
// 1.获取当前线程的stack
// 2.从stack中弹出对象
// 3.创建对象并绑定到stack
User user = RECYCLER.get();
user.recycle();
User user1 = RECYCLER.get();
System.out.println(user == user1);
}
}
true
3.1 Recycler
整个对象池的核心实现由ThreadLocal, Handler和Stack及WrakOrderQueue构成。
- Stack相当于是一级缓存,同一个线程内的使用和回收都将使用一个Stack
- 每个线程都会有一个自己对应的Stack,如果回收的线程不是Stack的线程,将元素放入到Queue中
- 所有的Queue组合成一个链表,Stack可以从这些链表中回收元素(实现了多线程之间共享回收的实例)
- get(): 获取对象
public final T get() {
if (maxCapacityPerThread == 0) {
return newObject((Handle<T>) NOOP_HANDLE);
}
Stack<T> stack = threadLocal.get();
DefaultHandle<T> handle = stack.pop();
if (handle == null) {
handle = stack.newHandle();
handle.value = newObject(handle);
}
return (T) handle.value;
}
- 拿到当前线程对应的stack
- 从stack中pop出一个元素
- 如果不为空则返回,否则创建一个新的实例
public final boolean recycle(T o, Handle<T> handle) {
if (handle == NOOP_HANDLE) {
return false;
}
DefaultHandle<T> h = (DefaultHandle<T>) handle;
if (h.stack.parent != this) {
return false;
}
h.recycle(o);
return true;
}
- Recycler的recycle方法主要做了一些参数验证。
3.2 Handler
recycle(): 放回池子中的方法, Recycler的recycle方法和DefaultHandle的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);
}
- Recycler的recycle方法主要做了一些参数验证。
- DefaultHandle的recycle方法:
- 如果当前线程是当前stack对象的线程, 放入stack。
- 获取当前线程对应的Map<Stack, WeakOrderQueue>, 实例放入stack对应的queue中。
3.3 Stack
Stack是对象池化背后存储实例的数据结构, 如果能从stack中拿到可用的实例就不再创建新的实例。
final Recycler<T> parent;
final WeakReference<Thread> threadRef;
final AtomicInteger availableSharedCapacity;
final int maxDelayedQueues;
private final int maxCapacity;
private final int ratioMask;
private DefaultHandle<?>[] elements;
private int size;
private int handleRecycleCount = -1; // Start with -1 so the first one will be recycled.
private WeakOrderQueue cursor, prev;
private volatile WeakOrderQueue head;
pop()
DefaultHandle<T> pop() {
int size = this.size;
// 如过size = 0, scavenge
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;
// 返回elements最后一个元素
return ret;
}
push(): 同线程和异步线程回收对象
同步线程回收对象
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;
}
异步线程回收对象
- 获取WeakOrderQueue
- 创建WeakOrderQueue
- 将对象追加到WeakOrderQueue
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;
}
// 创建WeakOrderQueue
if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {
// drop object
return;
}
delayedRecycled.put(this, queue);
} else if (queue == WeakOrderQueue.DUMMY) {
// drop object
return;
}
// 将对象追加到WeakOrderQueue
queue.add(item);
}
queue是一个队列形式, 节点为Link, Link中是Handler (处理逻辑)
3.4 WeakOrderQueue
head,tail:Link // 内部元素的指针(WeakOrderQueue内部存储的是一个Link的链表)
next:WeakOrderQueue // 指向下一个WeakOrderQueue的指针
owner:Thread // 对应的线程
WeakOrderQueue的结构图
WeakOrderQueue中是一个一个Link组成
add方法将元素添加到自身的“队列”中, transfer方法将自己拥有的元素“传输”到Stack中。
void add(DefaultHandle<?> handle) {
handle.lastRecycledId = id;
Link tail = this.tail;
int writeIndex;
if ((writeIndex = tail.get()) == LINK_CAPACITY) {
if (!head.reserveSpace(LINK_CAPACITY)) {
// Drop it.
return;
}
// We allocate a Link so reserve the space
this.tail = tail = tail.next = new Link();
writeIndex = tail.get();
}
tail.elements[writeIndex] = handle;
handle.stack = null;
// we lazy set to ensure that setting stack to null appears before we unnull it in the owning thread;
// this also means we guarantee visibility of an element in the queue if we see the index updated
tail.lazySet(writeIndex + 1);
}
add操作将元素添加到tail指向的Link对象中,如果Link已满则创建一个新的Link实例。
3.5 Link
static final class Link extends AtomicInteger {
// 处理逻辑Handler
private final DefaultHandle<?>[] elements = new DefaultHandle[LINK_CAPACITY];
// 读的指针
private int readIndex;
Link next;
}
Link内部包含了一个数组用于存放实例, 同时标记了读取位置的索引和下一个Link元素的指针。
4.总结
Recyler -> Stack-> WeakOrderQueue -> Link -> Handler文章来源:https://www.toymoban.com/news/detail-417093.html
文章来源地址https://www.toymoban.com/news/detail-417093.html
到了这里,关于[Netty源码] Netty轻量级对象池实现分析 (十三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!