gpt4 book ai didi

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

转载 作者:IT王子 更新时间:2023-10-28 23:35:48 26 4
gpt4 key购买 nike

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

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

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

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

操作系统是 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);
}
}

最佳答案

内存映射完全在操作系统中实现。 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% 的 writeback 意味着写程序将停止,直到他的脏百分比下降到 20% 以下。无论如何,数据将在 3000 厘秒或 30 秒后写入磁盘。


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


顺便说一句,您可能会觉得这门课很有趣。 MemoryStore允许您映射任何大小的内存,即 >> 2 GB 并对其执行线程安全操作。例如您可以跨进程共享内存。它支持堆外锁、 volatile 读/写、有序写和CAS。

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

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

关于java - 为什么 Java 内存映射缓冲区会导致大量意外磁盘 IO?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21748078/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com