ReferenceCounted的设计和ByteBuf的实现(AbstractReferenceCountedByteBuf)都不复杂。
但是对于如何使用ByteBuf, 在使用时候应该调用remain()/release()依然是个非常重要的话题。
原则
究竟应该谁,在申明时候来销毁ByteBuf?
netty的wiki中给出建议:
通常的经验是谁最后访问引用计数对象,谁就负责销毁它
具体来说是以下两点:
- 如果组件A把一个引用计数对象传给另一个组件B,那么组件A通常不需要销毁对象,而是把决定权交给组件B
- 如果一个组件不再访问一个引用计数对象,那么这个组件负责销毁它
做法
看了一下netty中的例子,对照上面的原则和做法,总结如下.
传递buffer对象不返回
对于A调用B的情况,如果B的函数不会返回Buffer对象,代码类似如下:
void a() {
ByteBuf buffer = createBuffer();
b(buffer);
}
void b(ByteBuf buffer) {}
会有以下几种情况:
如果A传递buffer对象到B之后,A就放弃对buffer的控制
之后只有B才控制(或者说访问)buffer,那么此时B就负有在使用完成之后销毁buffer的责任.
void a() { ByteBuf buffer = createBuffer(); b(buffer); } void b(ByteBuf buffer) { try { // handle buffer } finally { buffer.release(); } }
因此b需要遵循的原则: 如果有buffer传入,在使用完成之后需要销毁.
如果A传递buffer对象到B之后,A并没有放弃对buffer的控制
但是b是无法区分,b在被调用时是不知道a是否要放弃控制权,因此b只能继续遵循上述的原则做一次release.
此时a是知道自己的行为的,因此a可以在调用b之前,先行调用一次remain()方法. 这样a就可以在调用b之后继续保留对buffer的访问.
void a() { ByteBuf buffer = createBuffer(); buffer.remain(); try { b(buffer); // a continue to use buffer } finally { buffer.release(); } } void b(ByteBuf buffer) { try { // handle buffer } finally { buffer.release(); } }
传递buffer对象又被返回
对于A调用B的情况,如果B的函数会返回Buffer对象,代码类似如下:
void a() {
ByteBuf buffer = createBuffer();
buffer = b(buffer);
// continue to access buffer
}
ByteBuf b(ByteBuf buffer) {}
会有以下几种情况:
B在处理完成之后又将buffer原样返回,此时B不再控制buffer,而A在获取返回的buffer之后需要继续访问buffer,因此A才是最后的访问者,因此这时是A需要担负销毁buffer的责任
void a() { ByteBuf buffer = createBuffer(); try { buffer = b(buffer); // continue to access buffer } finally { buffer.release(); } } ByteBuf b(ByteBuf buffer) { // handle buffer return buffer; }
B在处理传入的buffer之后,又重新生成一个新的ByteBuf返回.此时对于A时无法判断返回的buffer对象和上面情况有什么不同,因此A只能继续遵循上述的原则对返回的ByteBuf做release(). 而B应该对输入的ByteBuf做release().
void a() { ByteBuf buffer = createBuffer(); try { buffer = b(buffer); // continue to access buffer } finally { buffer.release(); } } ByteBuf b(ByteBuf buffer) { try { // handle buffer } finally { buffer.release(); } ByteBuf newBuffer = createBuffer(); return newBuffer; }
特殊场景
阻止销毁
某些情况下,我们会在将ByteBuf传递出去之后阻止其他人对这个ByteBuf做销毁操作.
netty为此提供了一个特别的类UnreleasableByteBuf.