在Netty 4中直接使用内存

时间:2016-12-02 08:23:33

标签: java memory netty nio

我对Netty的直接内存管理存在疑问。

我通过以下方式创建一个直接缓冲区:

@GetMapping("/new/buffer/netty/unpool")
@Synchronized
public void newBufferNetty() {
    UnpooledByteBufAllocator allocator  = UnpooledByteBufAllocator.DEFAULT;
    ByteBuf buffer = allocator.buffer(100 * 1024 * 1024);
    _myByteBufList.add(buffer);
    log.info("buffer[{}] created", buffer);
}

然后我观察了top生成的信息,我发现内存没有变化(RES,SWAP和free)。我感到很困惑,因为如果我像N ByteBuffer.allocateDirect(1024*1024*100);一样以NIO方式进行操作,操作系统内存信息会改变。

在我调查了源代码之后,我发现NIO通过new DirectByteBuffer(cap)创建了一个directByteBuffer,而Netty实际上是通过new DirectByteBuffer(addr, cap)创建的。在后一种情况下,Netty没有打电话给Bits.reserve(size, cap),这就是我认为为什么top没有显示任何变化的原因。

我还发现Netty使用自己的计数器 DIRECT_MEMORY_COUNTER 来跟踪它分配的直接内存。

我的问题是:

  1. 为什么Netty在分配直接内存时不会调用Bits.reserve

  2. 为什么Netty必须使用自己的计数器来监控直接内存的使用?

  3. (这是让我最困惑的一个)为什么在创建Netty缓冲区时没有对os内存进行任何更改(UnpooledUnsafeNoCleanerDirectByteBuf)

  4. 非常感谢你。

1 个答案:

答案 0 :(得分:2)

我只回答3分。前2点只能由Netty作者解释。

如前所述,Netty使用new DirectByteBuffer(addr, cap)创建直接缓冲区。传递的内存地址是Unsafe.allocateMemory返回的一个调用系统内存分配工具的地址。如https://en.wikipedia.org/wiki/C_dynamic_memory_allocation

中所述
  

在延迟内存分配方案(例如Linux操作系统中常见的那些方案)中,大型堆不一定保留等效的系统内存;它只会在第一次写入时执行此操作(非映射内存页的读取返回零)。其粒度取决于页面大小。

因此,预计top不会反映Netty直接缓冲区分配。

相反,ByteBuffer.allocateDirect使用Unsafe.setMemory在使用Unsafe.allocateMemory分配后将所有字节设置为零。这种行为在Javadoc https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)

中指定
  

新缓冲区的位置将为零,其限制将是其容量,其标记将是未定义的,并且其每个元素将初始化为零。

它解释了ByteBuffer.allocateDirect通过top分配的原因。请注意,仅在首次使用已分配的内存后才会增加应用程序内存使用量。