最近用Netty框架開發網絡應用時,出現幾個異常報錯,仔細一看是內存泄漏了,提示ByteBuf對象在回收之前沒有調用ByteBuf.release()
ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected
出現這個問題是因為程序中生成了池化的ByteBuf(PooledByteBuf)。PooledByteBuf的內存空間是從內存池中分配的,並且內部維持了一個計數器,用來記錄引用次數。PooledByteBuf在使用完之后要手動調用release()函數,該函數會減小引用次數,減小到0時就會將內存歸還在內存池中。如果不調用release()函數,JVM不知道引用計數的存在,釋放該對象時,可能還有其他引用在使用該內存空間,該內存空間也無法歸還到內存池中,從而導致內存泄漏。
關於ByteBuf內存泄漏更詳細的資料請移步Netty中ByteBuf內存泄露及釋放解析
解決方法就是找到報錯的位置,找到生成的ByteBuf對象,在使用完之后調用對象的relesse()函數或者加上一句ReferenceCountUtil.release(msg)。如下面我出現的報錯
2020-06-12 17:04:41.242 [nioEventLoopGroup-2-1] ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:363)
io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187)
io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:123)
io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:872)
com.spring.netty.twg.service.TwgMessageDecoder.formatDecoder(TwgMessageDecoder.java:176)
com.spring.netty.twg.service.TwgMessageDecoder.getMessageBody(TwgMessageDecoder.java:90)
com.spring.netty.twg.service.TwgMessageDecoder.decode(TwgMessageDecoder.java:76)
io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:332)
io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
在formatDecoder函數中,我調用readBytes()函數生成新ByteBuf對象byteBufChar。
在使用結束時,調用byteBufChar的release()函數 byteBufChar.release();
2020-06-12 17:04:45.460 [nioEventLoopGroup-2-1] ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information. Recent access records: Created at: io.netty.buffer.SimpleLeakAwareByteBuf.unwrappedDerived(SimpleLeakAwareByteBuf.java:143) io.netty.buffer.SimpleLeakAwareByteBuf.retainedSlice(SimpleLeakAwareByteBuf.java:57) io.netty.handler.codec.LengthFieldBasedFrameDecoder.extractFrame(LengthFieldBasedFrameDecoder.java:498) io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:437) com.spring.netty.twg.service.TwgMessageDecoder.decode(TwgMessageDecoder.java:31) io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:332)
在decode函數中,我調用了父類的decode()函數,生成新BytyBuf對象in,
在使用結束時,調用工具類,幫助回收in對象 ReferenceCountUtil.release(in)或者直接調用release()