我对 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 来跟踪它分配的直接内存。
我的问题是:
为什么 Netty 在分配直接内存时不调用
Bits.reserve
?为什么 Netty 必须使用自己的计数器来监控直接内存的使用情况?
(这是最让我困惑的)为什么当我创建一个 Netty 缓冲区(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
不会反射(reflect) Netty 直接缓冲区分配。
相比之下,ByteBuffer.allocateDirect
使用Unsafe.setMemory
在使用Unsafe.allocateMemory
分配后将所有字节设置为零。此类行为在 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.
它解释了为什么 top
反射(reflect)了通过 ByteBuffer.allocateDirect
进行的分配。请注意,只有在首次使用分配的内存后,应用程序内存使用量才会增加。
关于java - Netty 4 中的直接内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40927651/