最近用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()