Netty内存泄漏原理

Netty在实现ByteBuf时采用了引用计数法进行ByteBuf的回收,使用引用计数法进行回收的ByteBuf都扩展了AbstractReferenceCountedByteBuf类,在使用AbstractReferenceCountedByteBuf时需要调用AbstractReferenceCountedByteBuf.retain方法递增引用计数器,在使用完毕时则需要调用AbstractReferenceCountedByteBuf.release方法递减引用计数器,当计数器为0时,会进行ByteBuf的回收工作:池化的ByteBuf不会进行实际的内存释放,会将占用的内存归还给内存池,非池化的ByteBuf则会直接释放内存(为了叙述简单,后面释放内存则指真正释放内存或者将内存归还给内存池)。

通过上面的描述可知,ByteBuf的正确回收依赖retain和release方法的正确调用,内存提前释放(即在使用ByteBuf时没有调用retain方法,导致提前释放)应用会报错,用户也能及时感知到;但是如果使用完ByteBuf忘了调用release则会导致内存不能及时得到回收,造成内存泄漏,且内存泄漏用户无法及时感知,久而久之就会发生OOM。为了解决这种问题,Netty采用了内存泄漏检测机制,发生内存泄漏时会通过日志将内存泄漏信息打印出来,报告给用户。

Netty的内存泄漏检测使用了WeakReference,即弱引用,了解过Java四种引用类型(强、软、弱、虚)和引用队列(ReferenceQueue)的读者知道,弱引用持有的对象会在虚拟机触发GC时(不管回收之后内存是否够用)被回收掉,如果使用具有引用队列参数的构造函数实例化WeakReference时,弱引用持有的对象在GC被回收时,弱引用自身会被放入引用队列。

在发生GC之前,调用clear方法手动清空弱引用持有的对象,发生GC后,弱引用也不会被放入引用队列中。

Netty中将普通ByteBuf转为具有内存泄漏检测功能的ByteBuf是通过AbstractByteBufAllocator.toLeakAwareBuffer方法实现的,我们直接在Eclipse中看该方法的调用层次即可知道Netty在哪里对ByteBuf进行了转换,该方法调用如下图所示:

可见池化内存分配器在分配heap或者direct ByteBuf时都进行了转换,非池化内存分配器仅在分配direct ByteBuf时进行了转换。个人理解时采用池化内存需要特别关注内存释放,否则为了实现池化内存预先分配的一大块内存会因为没有释放被很快分配完,造成后面没有内存进行分配。非池化分配的直接内存也需要特别注意释放,放置内存泄漏;非池化分配的heap内存(其实就是一个byte数组)则可以在对象被回收时同时被回收掉,发生内存泄漏的可能性较小。


我们看到AbstractByteBufAllocator.toLeakAwareBuffer对ResourceLeakDetector.track返回的DefaultResourceLeak和传入的ByteBuf对象进行封装,返回了具有内存泄漏检测功能的ByteBuf封装类SimpleLeakAwareCompositeByteBuf或其子类AdvancedLeakAwareCompositeByteBuf。如果应用程序在使用ByteBuf正确调用了retain和release方法,则在引用计数器为0时,则会清除弱引用持有的实际对象,发生GC时,DefaultResourceLeak也不会被放入引用队列中,但是如果应用程序在使用ByteBuf没有正确调用retain和release方法,则不会清除弱引用持有的实际对象,此时如果实际上已经没有强引用指向该ByteBuf,那么在发生GC时,垃圾收集器会回收该ByteBuf,而弱引用DefaultResourceLeak会被放入引用队列中,加入到引用队列中的就是识别到的发生内存泄漏的ByteBuf。在ResourceLeakDetector.track方法中调用的reportLeak输出的就是引用队列中的弱引用DefaultResourceLeak。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值