对象池其实就是缓存一些对象从而避免大量创建同一个类型的对象, 类似线程池。对象池缓存了一些已经创建好的对象, 避免需要的时候创建。同时限制了实例的个数。
池化技术最终要的就是重复的使用池内已经创建的对象。
如果创建一个对象的开销特别大, 那么需要提前创建一些可以使用的并缓存起来, 池化技术就是重复使用对象, 提前创建并缓存起来重复使用就是池化, 可以降低创建对象的开销。
会大量创建实例的场景, 重复的使用对象可以减少创建的对象数量, 降低GC的压力。
对于限制资源的使用更多的是一种保护机制, 比如数据库连接池, 除去创建对象本身的开销, 们对外部系统也会造成压力, 比如大量创建链接对DB也是有压力的。那么池化除了可以优化资源外, 本身限制了资源数, 对外部系统也起到了一层保护作用。
Apache Commons Pool, Netty轻量级对象池的实现。
Apache Commons Pool开源软件库提供了一个对象池API和一系列对象池的实现, 支持各种配置, 比如活跃对象数或者闲置对象个数等。DBCP数据库连接池基于Apache Commons Pool实现。
Netty自己实现了一套轻量级的对象池, 在多个IO线程独立工作时候, 基于NioEventLoop的实现, 每个IO线程轮询单独的Selector实例来检索IO事件, 在IO来临时候开始处理。最常见的IO操作就是读写, 具体到NIO就是从内核缓冲区拷贝数据到用户缓冲区或者从用户缓冲区拷贝数据到内核缓冲区。
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
整个对象池的核心实现由ThreadLocal, Handler和Stack及WrakOrderQueue构成。
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;
}
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;
}
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);
}
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;
}
异步线程回收对象
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 (处理逻辑)
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实例。
static final class Link extends AtomicInteger {
// 处理逻辑Handler
private final DefaultHandle<?>[] elements = new DefaultHandle[LINK_CAPACITY];
// 读的指针
private int readIndex;
Link next;
}
Link内部包含了一个数组用于存放实例, 同时标记了读取位置的索引和下一个Link元素的指针。
Recyler -> Stack-> WeakOrderQueue -> Link -> Handler