說明
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/:?]