根据这本书Netty in Action v10, reference counting是用来处理汇集的ByteBuf.但是JVM并不知道netty引用计数,所以JVM仍然可以GC ByteBuf.如果是这样,为什么我们仍然需要关心引用计数和手动调用release()方法?
我引用了<Netty in Action v10>中的一些来添加一些上下文.
引用计数的权衡之一是用户在使用消息时必须小心.虽然JVM仍然能够GC这样的消息(因为它不知道引用计数),但是这个消息不会被放回到之前可能获得它的池中.因此,如果您不仔细发布这些消息,那么在某一点上您将耗尽资源的可能性很大.
还有一些相关的线程: Netty 4中的缓冲区所有权:缓冲区生命周期是如何管理的?
https://blog.twitter.com/2013/netty-4-at-twitter-reduced-gc-overhead
(以下是我的理解.)
A ByteBuf可以从2个角度分类:
1. Pooled or Unpooled
2. Heap-based or Direct
Run Code Online (Sandbox Code Playgroud)
所以可以有4种组合:
(a) Pooled Heap-based
(b) Pooled Direct
(c) Unpooled Heap-based
(d) Unpooled Direct
Run Code Online (Sandbox Code Playgroud)
只有(a)和(c)受JVM GC机制的影响,因为它们是基于堆的.
在<Netty in Action v10>的上述引文中,我认为该消息意味着一个Java对象,它位于(a)类别中.
一个最终的规则是,如果一个Java对象是GCed,它就完全消失了.以下是我认为Netty的作用:
对于(a),Netty分配器必须诱使JVM GC相信该对象永远不应该被GC.然后使用ref count将对象移出/移回池中.这是生命周期的另一种形式.
对于(b),不涉及JVM GC,因为它不是基于JVM堆的.并且Netty分配器需要使用ref计数来将对象移出/返回池中.
对于(c),JVM GC负责控制对象的生命.Netty allocator只提供分配对象的API.
对于(d),不涉及JVM GC.并且不需要汇集.所以Netty allocator只需要提供API来分配/释放对象.
我已经阅读了各种StackOverFlow QA以及有关Netty内存泄漏的外部链接和博客,从ReferenceCountedObjects和ManuallyHandlingReferenceCounting,BufferOwnership,TwitterBlog,ChannelOutboundHandlerFlushedBufferLeak以及源自这些页面的其他链接开始.
我理解如果应用程序在完成资源后不释放资源,实际内存本身将被GC,但Netty的池大小仍会增加并导致内存泄漏.
上面链接解释这一点的引用引用"即使缓冲区本身是垃圾收集,用于存储池的内部数据结构也不会.","PooledByteBufAllocator也使用Recycler来"汇集"ByteBuf容器(不是它指的是自己的记忆.)"
有人可以解释一下如何发生这种情况吗?如果ByteBuf是一个引用内存的容器,那么在ByteBuf仍然在Netty内存池中时如何收集内存?我想象Netty维护了一个ByteBuf(s)池,并在它的引用计数变为0时重用它所引用的内存.通过这个假设,我无法理解如果内存本身ByteBuf仍然存在于Netty的池中,它是如何被GC 的?
有人可以用简单的语言澄清一下吗?