本文是在netty权威指南的基础上写的。原书作者因篇幅原因没有深入讨论源码。个人在此作不定期的补充。
PooledDirectByteBuf基于内存池实现,与UnPooledDirectByteBuf的唯一不同就是缓冲区的分配和销毁策略不同,其他功能都是等同的,也就是说,两者唯一的不同就是内存分配策略不同。
1.创建字节缓冲区实例由于采取内存池实现,所以新创建PooledDirectByteBuf对象时不能直接new一个实例,而是从内存池中获取,然后设置引用计数器的值。
static PooledDirectByteBuf newInstance(int maxCapacity) {
PooledDirectByteBuf buf = RECYCLER.get();//从内存池中获取对象
buf.setRefCnt(1);//设置引用计数器
buf.maxCapacity(maxCapacity);
return buf;
}
直接从内存池Recycler
PooledDirectByteBuf维护了一个Recycler内存池。重写覆盖了 protected abstract T newObject(Handle
private static final Recycler RECYCLER = new Recycler() {
@Override
protected PooledDirectByteBuf newObject(Handle handle) {
return new PooledDirectByteBuf(handle, 0);
}
};
RECYCLER的get()方法会先从stack中获取对象,如果对象不存在则调用重写的newObject(Handle
然后具体来看这个对象内存池Recycler
首先是一个内部接口 Handle
public interface Handle {
void recycle(T object);
}
接着就是一个静态内部类Stack
static final class Stack implements Handle {
private static final int INITIAL_CAPACITY = 256;
final Recycler parent;
final Thread thread;
private T[] elements;//底层使用数组实现存储
private int size;
private final Map map = new IdentityHashMap(INITIAL_CAPACITY);
@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
Stack(Recycler parent, Thread thread) {
this.parent = parent;
this.thread = thread;
elements = newArray(INITIAL_CAPACITY);
}
@Override
public void recycle(T object) {
parent.recycle(object, this);
}
T pop() {
int size = this.size;
if (size == 0) {
return null;
}
size --;
T ret = elements[size];
elements[size] = null;
map.remove(ret);
this.size = size;
return ret;
}
void push(T o) {
if (map.put(o, Boolean.TRUE) != null) {
throw new IllegalStateException("recycled already");
}
int size = this.size;
if (size == elements.length) {
T[] newElements = newArray(size << 1);
System.arraycopy(elements, 0, newElements, 0, size);
elements = newElements;
}
elements[size] = o;
this.size = size + 1;
}
@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
private static T[] newArray(int length) {
return (T[]) new Object[length];
}
}
Recycler
ThreadLocal类接口很简单,只有4个方法:
void set(T value)设置当前线程的线程局部变量的值。
public T get()该方法返回当前线程所对应的线程局部变量。
public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
protected T initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(T)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
关于ThreadLocal最后说一点,ThreadLocal不是用来解决对象共享访问问题的,它仅仅只是让各个线程都拥有了各自的对象。threadLocal本身仅仅只是作为一个key来帮助存储目标对象,它跟目标对象没有任何的联系仅仅只是些关于ThreadLocalMap操作方法。目标对象通过Thread中的ThreadLocalMap跟线程关联。所以不需要考虑在threadLocal上面的同步问题,除非你在线程方法中去修改threadLocal自身的一些状态,但这根本没必要。所以将它设置为静态变量就可以了免得每个线程都会有个threadLocal而浪费资源。多个线程共用一个threadLocal,但各个线程都拥有独立的目标对象。
调用copy(int index, int length)可以复制一个新的实例,与原来的PooledDirectByteBuf独立
@Override
public ByteBuf copy(int index, int length) {
checkIndex(index, length);
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
copy.writeBytes(this, index, length);
return copy;
}
首先是索引和长度的合法性校验。然后调用PooledByteBufAllocator分配一个新的ByteBuf。PooledByteBufAllocator没有实现directBuffer(int initialCapacity, int maxCapacity),所以最终会调用AbstractByteBufAllocator的directBuffer(int initialCapacity, int maxCapacity)
@Override
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
validate(initialCapacity, maxCapacity);
return newDirectBuffer(initialCapacity, maxCapacity);//由子类去实现具体的策略
}
上面的 newDirectBuffer(initialCapacity, maxCapacity)对于不同的子类有不同的实现策略,如果是基于内存池的分配器,它会从内存池中获得可用的ByteBuf,如果是非内存池,则会直接创建新的byteBuf
基于内存池的缓冲区分配(PooledByteBufAllocator中):
@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena directArena = cache.directArena;
ByteBuf buf;
if (directArena != null) {
buf = directArena.allocate(cache, initialCapacity, maxCapacity);//从内存池中获取
} else {
if (PlatformDependent.hasUnsafe()) {
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
}
return toLeakAwareBuffer(buf);
}
基于非内存池的缓冲区分配(UnpooledByteBufAllocator中):
@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
ByteBuf buf;
if (PlatformDependent.hasUnsafe()) {
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);//直接new创建一个新的
}
return toLeakAwareBuffer(buf);
}
ByteBuf汇总的一些接口是跟具体子类实现相关的,不同的子类功能是不同的。正如UnpooledHeapButeBuf,PooledDirectByteBuf也有子类实现相关功能。当我们操作子类实现相关方法时,需要对是否支持这些操作进行判断,否则会导致异常。
@Override
public boolean hasArray() {
return false;
}
@Override
public byte[] array() {
throw new UnsupportedOperationException("direct buffer");
}
@Override
public int arrayOffset() {
throw new UnsupportedOperationException("direct buffer");
}
@Override
public boolean hasMemoryAddress() {
return false;
}
@Override
public long memoryAddress() {
throw new UnsupportedOperationException();
}