如果不调用释放函数,了解Netty内存泄漏的原因

9
我已经阅读了各种与Netty中的内存泄漏相关的StackOverFlow QAs、外部链接和博客,从ReferenceCountedObjectsManuallyHandlingReferenceCountingBufferOwnershipTwitterBlogChannelOutboundHandlerFlushedBufferLeak等链接开始。

我明白,如果应用程序在使用完资源后不释放它,则实际内存本身将被GC,但仍然会增加Netty的池大小并导致内存泄漏。

以上链接中的一些引用解释了这一点:“即使缓冲区本身被垃圾收集,用于存储池的内部数据结构也不会被回收。”,“PooledByteBufAllocator也使用Recycler来“池化”ByteBuf容器(而不是它所指向的内存)。”

请问有人能更详细地解释一下这是如何发生的吗?如果ByteBuf是一个容器,它引用了一个内存,那么当ByteBuf仍然存在于Netty内存池中时,内存如何被回收?我想象Netty维护了一个ByteBuf的池,并在其引用计数变为0时重用它所引用的内存。基于这个假设,我无法理解如果ByteBuf仍然存在于Netty的池中,内存本身如何被GC。

请有人以简单的方式澄清一下吗?

1个回答

5
让我来澄清一下……基本上,Netty在内存本身和其周围的容器中使用不同的池。
这里的容器是ByteBuf。Netty在Recycler中对ByteBuf进行池化(这基本上是一个对象池)。需要注意的重要事情是它将对实际底层存储(也称为存储)的引用“null”掉,以便实际存储字节。
字节本身(通过ByteBuf容器公开)存在于不同的池中。此池仅保存ByteBuf的后备存储,而不保存ByteBuf本身。后备存储可以在堆上(byte[])或堆外(本机/直接内存)上。
因此,理论上这两者都可能导致内存泄漏。在实践中,大多数内存泄漏是由于未调用ByteBuf.release()而导致后备存储泄漏。

Norman,ByteBuf在deallocate方法中将实际底层内存“null”出来,对吗?当ByteBuf完全释放并且refcnt变为0时才会调用deallocate方法。我是对的吗?我的主要疑问是,当ByteBuf没有完全释放时,底层内存如何被GCed。我知道资源应该被释放。如果没有释放,实际内存和ByteBuf容器都不应该被GCed。这个问题的重点是理解,“当ByteBuf没有完全释放时,底层内存如何被GCed?” - Amudhan
你是在问我们如何在这里实现泄漏检测器吗? - Norman Maurer
Norman,非常感谢您的关注。我并不是在询问完整的内部实现细节。但是您能否请好心概念性地解释一下呢?我的意思是,当ByteBuf容器所引用的底层存储器没有被完全释放时,该如何将其GC掉?当ByteBuf的refcnt达到0时,ByteBuf才将底层存储器的引用置空。直到refcnt达到0之前,ByteBuf仍然持有对底层存储器的引用。那么,在ByteBuf没有完全释放的情况下,底层存储器是如何被GC的呢?提前致谢! - Amudhan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接