有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

linux为什么Java内存映射缓冲区会导致大量意外的磁盘IO?

我已经编写了一些Posix程序,利用映射文件缓冲区。一个简单的场景是将1GB文件映射到内存中,并用内容填充整个文件

在程序执行期间,在msyncmunmap调用发生之前,几乎没有磁盘IO

在完全相同的系统上,我用Java编写了在Oracle JDK 7上运行的等效程序,并注意到在整个程序执行过程中有大量的磁盘IO活动

在JVM中,内存映射文件缓冲区是如何以不同的方式实现的?有没有办法推迟大规模的IO活动

操作系统是Linux 3.2 x64

代码:

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Main {
public static void main(String[] args) throws Exception {
    long size = 1024 * 1048576;
    RandomAccessFile raf= new RandomAccessFile("mmap1g", "rw");
    FileChannel fc = raf.getChannel();
    MappedByteBuffer buf = fc.map(FileChannel.MapMode.READ_WRITE, 0, size);
    for(long i = 0; i < size; ++i)
        buf.put((byte)1);
}
}

共 (1) 个答案

  1. # 1 楼答案

    内存映射完全在操作系统中实现。JVM对如何将其刷新到磁盘没有发言权,除非在选择文件时使用force()方法和"rws"选项

    Linux将根据sysctl中设置的内核参数刷新到磁盘

    $ sysctl -a | grep dirty
    vm.dirty_background_bytes = 0
    vm.dirty_background_ratio = 10
    vm.dirty_bytes = 0
    vm.dirty_expire_centisecs = 3000
    vm.dirty_ratio = 20
    vm.dirty_writeback_centisecs = 500
    

    这些是我笔记本电脑上的默认设置。比率10意味着当10%的主内存脏时,它将开始在后台将数据写入磁盘。写回20%意味着写程序将停止,直到脏百分比降至20%以下。在任何情况下,数据都将在3000厘米秒或30秒后写入磁盘


    一个有趣的比较是,它将文件映射到tmpfs文件系统上的内存。我已经安装了/tmp作为tmpfs,但大多数系统都有/dev/shm


    顺便说一句,你可能会觉得这门课很有趣MemoryStore允许您映射任意大小的内存,即>>;2 GB,并在其上执行线程安全操作。e、 g.您可以跨进程共享内存。它支持堆外锁、易失性读/写、有序写和CAS

    我有一个测试,其中两个进程锁定、切换和解锁记录,在我的笔记本电脑上平均延迟50纳秒

    BTW2:Linux有稀疏的文件,这意味着你可以在比你的主内存大的区域映射,而且比你的可用磁盘空间大。e、 g.如果映射为8 TB,并且只使用4 GB的随机片段,那么它将在内存中使用最多4 GB,在磁盘上使用最多4 GB。如果使用du {file},可以看到实际使用的空间。注意:延迟分配磁盘空间可能会导致文件高度碎片化,这可能是HDD的性能问题