说明
io.netty.buffer.ByteBuf实现了io.netty.util.ReferenceCounted接口,需要显式释放。当ByteBuf被实例化后,它的引用计数是1。
调用ByteBuf对象的release方法释放:
- ByteBuf的release()方法使引用计数减少1。只有当执行以后引用计数减少到0,该函数才返回true。当ByteBuf的引用计数减少到0时,ByteBuf会被释放。
- 当ByteBuf的引用计数是0时,再执行release()方法会抛出IllegalReferenceCountException异常。
调用ReferenceCountUtil的方法释放:
- release(Object msg):如果要被释放的对象msg实现了ReferenceCounted接口,那么内部会调用该对象的release()方法,并返回执行release()方法的结果。如果要被释放的对象msg没有实现ReferenceCounted接口,那么直接返回false。
- safeRelease(Object msg):当要被释放的对象实现了ReferenceCounted接口,内部调用对象的release()方法来释放;如果对象的当前引用计数是0时,如果执行该函数,不会抛出异常,而是打印告警日志。如果要被释放的对象没有实现ReferenceCounted接口,执行该函数不会有任何作用。
代码示例
执行ByteBuf的release()返回结果观察
package com.thb;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;public class Demo {public static void main(String[] args) {// 创建一个ByteBufByteBuf buf = Unpooled.buffer();// 引用计数加1buf.retain();// 此时的引用计数是2System.out.println("buf.refCnt: " + buf.refCnt());// 此时执行buf.release()返回false,因为执行以后的引用计数变成1System.out.println("buf.release: " + buf.release());// 此时的引用计数是1System.out.println("buf.refCnt: " + buf.refCnt());System.out.println("buf.release: " + buf.release());// 此时执行buf.release()返回true,因为执行以后的引用计数变成0System.out.println("buf.refCnt: " + buf.refCnt()); }}
运行输出:
buf.refCnt: 2
buf.release: false
buf.refCnt: 1
buf.release: true
buf.refCnt: 0
ByteBuf的引用计数是0时,再执行release()方法会抛出IllegalReferenceCountException异常
package com.thb;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;public class Demo {public static void main(String[] args) {// 创建一个ByteBufByteBuf buf = Unpooled.buffer();// 此时的引用计数是1System.out.println("buf.refCnt: " + buf.refCnt());// 此时执行buf.release()返回true,因为执行以后的引用计数变成0System.out.println("buf.release: " + buf.release());// 此时的引用计数是0System.out.println("buf.refCnt: " + buf.refCnt());// ByteBuf的引用计数已经变成0,再执行release()函数会抛出IllegalReferenceCountException异常System.out.println("buf.release: " + buf.release());}}
运行结果:
buf.refCnt: 1
buf.release: true
buf.refCnt: 0
Exception in thread "main" io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:83)at io.netty.util.internal.ReferenceCountUpdater.release(ReferenceCountUpdater.java:148)at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:101)at com.thb.Demo.main(Demo.java:19)
调用ReferenceCountUtil的release(Object msg)方法释放
package com.thb;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;public class Demo {public static void main(String[] args) {// 创建一个ByteBufByteBuf buf = Unpooled.buffer();// 此时的引用计数是1System.out.println("buf.refCnt: " + buf.refCnt());// 此时执行ReferenceCountUtil.release(buf)返回true,因为执行以后的引用计数变成0System.out.println("ReferenceCountUtil.release: " + ReferenceCountUtil.release(buf));// 此时的引用计数是0System.out.println("buf.refCnt: " + buf.refCnt());}}
运行输出:
buf.refCnt: 1
ReferenceCountUtil.release: true
buf.refCnt: 0
用ReferenceCountUtil的release(Object msg)释放一个引用计数为0的对象,抛出异常
package com.thb;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;public class Demo {public static void main(String[] args) {// 创建一个ByteBufByteBuf buf = Unpooled.buffer();// 此时的引用计数是1System.out.println("buf.refCnt: " + buf.refCnt());// 此时返回true,因为执行以后的引用计数变成0System.out.println("ReferenceCountUtil.release: " + ReferenceCountUtil.release(buf));// 此时的引用计数是0System.out.println("buf.refCnt: " + buf.refCnt());// 抛出异常,因为在执行调用前,buf当前的引用计数已经是0了System.out.println("ReferenceCountUtil.release: " + ReferenceCountUtil.release(buf));}}
运行输出:
buf.refCnt: 1
Exception in thread "main" io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:83)at io.netty.util.internal.ReferenceCountUpdater.release(ReferenceCountUpdater.java:148)at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:101)at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:90)at com.thb.Demo.main(Demo.java:21)
ReferenceCountUtil.release: true
buf.refCnt: 0
调用ReferenceCountUtil的release(Object msg)方法释放一个没有实现ReferenceCounted接口的对象,结果为false
package com.thb;import io.netty.util.ReferenceCountUtil;public class Demo {public static void main(String[] args) {String msg = "hello";// 此时返回false,因为对象是String类型,没有实现ReferenceCounted接口System.out.println("ReferenceCountUtil.release: " + ReferenceCountUtil.release(msg));}}
运行输出:
调用ReferenceCountUtil的safeRelease(Object msg)方法释放实现了ReferenceCounted接口的对象;如果对象当前引用计数为0,打印告警日志
package com.thb;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;public class Demo {public static void main(String[] args) {// 创建一个ByteBufByteBuf buf = Unpooled.buffer();// 此时的引用计数是1System.out.println("buf.refCnt: " + buf.refCnt());// 正常释放ReferenceCountUtil.safeRelease(buf); // 此时的引用计数是0System.out.println("buf.refCnt: " + buf.refCnt());// buf的引用计数已经在0了,再释放会打印告警日志ReferenceCountUtil.safeRelease(buf);}}
运行输出:
buf.refCnt: 1
buf.refCnt: 0
14:55:40.222 [main] WARN io.netty.util.ReferenceCountUtil - Failed to release a message: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed)
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:83) ~[classes/:?]at io.netty.util.internal.ReferenceCountUpdater.release(ReferenceCountUpdater.java:148) ~[classes/:?]at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:101) ~[classes/:?]at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:90) ~[classes/:?]at io.netty.util.ReferenceCountUtil.safeRelease(ReferenceCountUtil.java:116) [classes/:?]at com.thb.Demo.main(Demo.java:20) [classes/:?]