在Netty 4中直接使用内存

rua*_*hao 5 java memory nio netty

我有一个关于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);
}
Run Code Online (Sandbox Code Playgroud)

然后我观察了生成的信息top,我发现内存没有变化(RES,SWAP和free).我很困惑,因为它是好的(操作系统内存信息会改变),如果我用NIO方式做的话ByteBuffer.allocateDirect(1024*1024*100);.

在我调查了源代码之后,我发现NIO创建了一个directByteBuffer,new DirectByteBuffer(cap)而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)

非常感谢你提前.

小智 3

我只回答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.allocateMemoryJavadoc https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)中指定了此类行为

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

它解释了为什么分配viaByteBuffer.allocateDirect由 反映top。请注意,应用程序内存使用量仅在首次使用分配的内存后才会增加。