【问题标题】:Direct memory usage in Netty 4Netty 4 中的直接内存使用
【发布时间】:2018-03-22 18:28:38
【问题描述】:

我对 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)。我很困惑,因为如果我以像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缓冲区(UnpooledUnsafeNoCleanerDirectByteBuf)时os内存没有变化

非常感谢您。

【问题讨论】:

    标签: java memory netty nio


    【解决方案1】:

    我只回答 3 分。前两点只能由 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 反映。请注意,只有在首次使用分配的内存后才会增加应用程序的内存使用量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-08
      • 1970-01-01
      • 1970-01-01
      • 2013-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多