ByteBuffer.allocateDirect()和MappedByteBuffer.load()的区别

15
我试图通过使用MappedByteBuffer将特定文件内存映射来实现两个或多个JVM之间的共享缓存。从规范中可以看出,当我们使用MappedByteBuffer.load()时,它应该将数据加载到直接缓冲区中。关于此,我有几个问题。
我的代码片段:
RandomAccessFile file = new RandomAccessFile("file.txt","rw");
FileChannel fc = file.getChannel();
MappedByteBuffer buf5 = fc.map(MapMode.READ_WRITE, 0, fc.size());

//ByteBuffer buf6 = ByteBuffer.allocateDirect(100000000);

buf5.load();

try
{
    Class c = Class.forName("java.nio.Bits");
    Field f = c.getDeclaredField("reservedMemory");
    f.setAccessible(true);
    long reservedMemory = f.getLong(null);
    f = c.getDeclaredField("maxMemory");
    f.setAccessible(true);
    System.out.println(
            "Direct Memory Usage: "+ reservedMemory +"/"+ f.getLong(null)+"\n");
}
catch (Throwable t)
{
}
  1. The output of the above code is 0 byte for the Direct Memory Usage (File.txt is 1 GB). But if I uncomment the line ..

    ByteBuffer buf6 = ByteBuffer.allocateDirect(100000000);
    

    I get a Direct Memory Usage of 100MB . Not able to understand why is this so, as to why I am not getting any direct memory usage in the first place ( i.e. when the line is commented out )

  2. Although the Direct Memory Usage is 0 B for the above code, I do see that the resident memory ( using unix top ) of the process increase by 1 GB. But if I do a "free -m" on the box, I do not see any increase in memory usage.

在这两种情况下,我有点困惑内存最终停留在哪里。
谢谢!
1个回答

27
直接字节缓冲区(使用ByteBuffer.allocateDirect分配的缓冲区)与MappedByteBuffers不同,因为它们代表不同的内存部分并以不同的方式分配。直接字节缓冲区是访问在JVM外部分配的一块内存的方式,通常使用malloc调用进行分配(尽管大多数实现可能会使用高效的slab分配器)。也就是说,它只是指向一块内存的指针。
MappedByteBuffer表示使用mmap调用分配的内存节​​段,该调用用于执行内存映射I/O。因此,MappedByteBuffers不会像Direct ByteBuffer一样注册其对内存的使用。
因此,尽管两者都是“直接”的,因为它们表示JVM外的内存,但它们的目的不同。
顺便提一下,为了获取reservedMemory值,您正在反射地调用JVM的内部方法,其实现未受任何规范的约束,因此不能保证该值的返回内容。可以使用C/C++中的NewDirectByteBuffer调用从JNI中分配Direct ByteBuffers(可能会使用MappedByteBuffers),这可能不会影响reservedMemory值,该值仅在使用Java ByteBuffer.allocateDirect时才会更改。

感谢您的回复,Michael。是的,看起来当我们使用mappedByteBuffer时,保留的内存值并没有受到影响。但是,我仍然困惑于当我将文件映射并加载到内存中时,内存实际上到底去了哪里,因为驻留内存和虚拟内存都增加了,但是在Linux系统中,“free -m”并没有显示出任何内存增加。 - sim
3
内存映射文件计入虚拟内存而非物理内存,因此预计虚拟内存使用量会增加。值得注意的是,在确定进程使用多少物理内存方面(至少在Linux中)非常困难,因此驻留大小可能包括内存映射,即使实际上并未消耗太多物理内存。这就是为什么free不显示任何额外内存消耗的原因。 - Michael Barker
1
谢谢Michael。是的,我认为免费版不包括内存映射文件在显示盒子使用情况时。/proc/meminfo给了我想要的信息。 - sim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接