Netty 4 中的直接内存使用
Direct memory usage in Netty 4
我对 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 方式进行操作,那没关系(OS 内存信息会改变)
查了一下源码,发现NIO是new DirectByteBuffer(cap)
创建directByteBuffer,而Netty是new DirectByteBuffer(addr, cap)
创建的。在后一种方式中,Netty 没有调用 Bits.reserve(size, cap)
,这就是我认为 top
.
没有显示任何变化的原因
而且我还发现 Netty 使用它自己的计数器 DIRECT_MEMORY_COUNTER 来跟踪它分配的直接内存。
我的问题是:
为什么分配直接内存时Netty不调用Bits.reserve
?
为什么Netty必须使用自己的计数器来监控直接内存的使用情况?
(这是让我困惑的most)为什么当我创建Netty缓冲区时os内存没有变化(UnpooledUnsafeNoCleanerDirectByteBuf)
非常感谢您。
我只回答3分。前两点只能由Netty作者解释。
正如问题中提到的,Netty 使用 new DirectByteBuffer(addr, cap)
来创建直接缓冲区。并且传递的内存地址是由 Unsafe.allocateMemory
返回的,它调用系统内存分配工具。正如https://en.wikipedia.org/wiki/C_dynamic_memory_allocation
中所说
On lazy memory allocation schemes, such as those often found in the Linux operating system, a large heap does not necessarily reserve the equivalent system memory; it will only do so at the first write time (reads of non-mapped memory pages return zero). The granularity of this depends on page size.
因此,预计top
不会反映 Netty 直接缓冲区分配。
相比之下,ByteBuffer.allocateDirect
在使用 Unsafe.allocateMemory
分配后使用 Unsafe.setMemory
将所有字节设置为零。这种行为在 Javadoc https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)
中指定
The new buffer's position will be zero, its limit will be its capacity, its mark will be undefined, and each of its elements will be initialized to zero.
它解释了为什么通过 ByteBuffer.allocateDirect
进行的分配会被 top
反映出来。请注意,只有在首次使用分配的内存后,应用程序内存使用量才会增加。
我对 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是new DirectByteBuffer(cap)
创建directByteBuffer,而Netty是new DirectByteBuffer(addr, cap)
创建的。在后一种方式中,Netty 没有调用 Bits.reserve(size, cap)
,这就是我认为 top
.
而且我还发现 Netty 使用它自己的计数器 DIRECT_MEMORY_COUNTER 来跟踪它分配的直接内存。
我的问题是:
为什么分配直接内存时Netty不调用
Bits.reserve
?为什么Netty必须使用自己的计数器来监控直接内存的使用情况?
(这是让我困惑的most)为什么当我创建Netty缓冲区时os内存没有变化(UnpooledUnsafeNoCleanerDirectByteBuf)
非常感谢您。
我只回答3分。前两点只能由Netty作者解释。
正如问题中提到的,Netty 使用 new DirectByteBuffer(addr, cap)
来创建直接缓冲区。并且传递的内存地址是由 Unsafe.allocateMemory
返回的,它调用系统内存分配工具。正如https://en.wikipedia.org/wiki/C_dynamic_memory_allocation
On lazy memory allocation schemes, such as those often found in the Linux operating system, a large heap does not necessarily reserve the equivalent system memory; it will only do so at the first write time (reads of non-mapped memory pages return zero). The granularity of this depends on page size.
因此,预计top
不会反映 Netty 直接缓冲区分配。
相比之下,ByteBuffer.allocateDirect
在使用 Unsafe.allocateMemory
分配后使用 Unsafe.setMemory
将所有字节设置为零。这种行为在 Javadoc https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)
The new buffer's position will be zero, its limit will be its capacity, its mark will be undefined, and each of its elements will be initialized to zero.
它解释了为什么通过 ByteBuffer.allocateDirect
进行的分配会被 top
反映出来。请注意,只有在首次使用分配的内存后,应用程序内存使用量才会增加。