我遇到了一个问题,我创建了大小为1KB的MappedByteBuffer
,然后滑过一个大小为20MB的文件。
for(20MB file) {
writeBuffer = fc.map(MapMode.READ_WRITE, writeIndex, mappingSize);
// write data into the writeBuffer
//update to new write index
}
在这种情况下,我已经创建了一大堆1KB MappedByteBuffer
,我认为可以在文件中向前移动时重复使用,这显然不是这里的情况,因为我在一段时间之后遇到了OOM。
但是,当我编辑mappingSize并使其为上述相同代码的128KB时,测试运行正常(没有OOM)。
有人可以解释MappedByteBuffer
的缓冲区大小如何影响系统分配和回收资源的方式(在这种情况下是内存)?
答案 0 :(得分:0)
没有明确定义的时间可以释放基础MappedByteBuffers的VM映射。所以永远不会发布。所以你使用的越少越好。
答案 1 :(得分:0)
看起来你达到了max_map_count限制。它是Linux进程可以创建的最大映射数。这可以通过root使用sysctl -w vm.max_map_count=XXX
进行更改。
在Java中,未引用的MappedByteBuffers和底层文件映射在GC之前永远不会发布。但只有当您的Java堆内存不足时才会触发GC(忽略分配的本机内存量)。这意味着您可以创建数千个不会自动释放的未引用的MappedByteBuffers。顺便说一句,有一个黑客可以使用非公共API手动释放它们:
((sun.nio.ch.DirectBuffer) mappedByteBuffer).cleaner().clean();
此外,映射1K区域没有任何意义,因为OS文件映射始终是页面对齐的,即起始地址和大小始终是4096字节的倍数。
P.S。
当Java在失败的map()
上强制GC以释放未引用缓冲区占用的内存时,会出现一种特殊情况。见FileChannelImpl.java。但是,如果您通过JVM选项禁用显式GC,那么您就遇到了麻烦。