引用计数是一种通过在某个对象所持有的资源不再被其他对象引用时释放该对象所持有的资源来优化内存使用和性能的技术。Netty 在第4 版中为ByteBuf 和ByteBufHolder 引入了引用计数技术,它们都实现了interface ReferenceCounted。
引用计数背后的想法并不是特别的复杂;它主要涉及跟踪到某个特定对象的活动引用的数量。一个ReferenceCounted 实现的实例将通常以活动的引用计数为1 作为开始。只要引用计数大于0,就能保证对象不会被释放。当活动引用的数量减少到0 时,该实例就会被释放。注意,虽然释放的确切语义可能是特定于实现的,但是至少已经释放的对象应该不可再用了。
引用计数对于池化实现(如PooledByteBufAllocator)来说是至关重要的,它降低了内存分配的开销。代码清单5-15 和代码清单5-16 展示了相关的示例。
/**
* Listing 5.15 Reference counting
*/
@Test
public void referenceCounting() {
Channel channel = CHANNEL_FROM_SOMEWHERE; //get reference form somewhere
// 从Channel 获取ByteBufAllocator
ByteBufAllocator allocator = channel.alloc();
//...
// 从ByteBufAllocator分配一个ByteBuf
ByteBuf buffer = allocator.directBuffer();
// 检查引用计数是否为预期的1
assert buffer.refCnt() == 1;
buffer.release();
//...
}
/**
* Listing 5.16 Release reference-counted object
*/
public static void releaseReferenceCountedObject() {
ByteBuf buffer = Unpooled.buffer(1024); //get reference form somewhere
// 减少到该对象的活动引用。当减少到0 时,该对象被释放,并且该方法返回true
boolean released = buffer.release();
//...
}
试图访问一个已经被释放的引用计数的对象,将会导致一个IllegalReferenceCountException。
注意,一个特定的(ReferenceCounted 的实现)类,可以用它自己的独特方式来定义它的引用计数规则。例如,我们可以设想一个类,其release()方法的实现总是将引用计数设为零,而不用关心它的当前值,从而一次性地使所有的活动引用都失效。
谁负责释放 一般来说,是由最后访问(引用计数)对象的那一方来负责将它释放。
ReferenceCountUtil辅助类
引用计数辅助类,操作时会先判断对象是否为ReferenceCounted
public final class ReferenceCountUtil {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountUtil.class);
@SuppressWarnings("unchecked")
public static <T> T retain(T msg) {
if (msg instanceof ReferenceCounted) {
return (T) ((ReferenceCounted) msg).retain();
}
return msg;
}
public static boolean release(Object msg) {
if (msg instanceof ReferenceCounted) {
return ((ReferenceCounted) msg).release();
}
return false;
}
}
网友评论