内存映射文件

简介: 内存映射文件

基本思想

进程通过系统调用将一个文件或文件的部分映射到进程的虚拟地址空间的一部分,访问这个文件就像访问内存中的一个大数组,而不是对文件进行读写。

实现

在多数实现中,在影射共享的页面时不会涉及读入页面的内容,而是在访问页面时页面才会被每次一页读入,磁盘文件则被当做后备存储。

分类

内存映射文件主要有两个分类:持久化(Persisted)和非持久化(Non-persisted)

持久化

持久化文件时,当进程退出或显示地解除文件映射时,所有修改页面会写回映射的文件中。

非持久化

非持久化时,文件并不关联硬盘文件。当关闭内存映射文件时,所有数据被抛弃。非持久化适用于进程通信的共享内存。

在Windows操作系统中,不需要调用CreateFile。调用CreateFileMapping时,将INVALID_HANDLE_VALUE作为hFile参数传入,这表示创建的文件映射不是磁盘文件,而是页交换文件。

图例

Image.png

应用场景

大文件读写

如果是小文件,那么内存映射文件会导致碎片空间浪费,因为内存映射以页为单位加载数据,一般内存中一页通常至少要4KB。因此一个5KB的文件需要映射到内存需要两页,也就是8KB,从而浪费了3KB内存空间。

操作系统加载进程

多进程共享内存

Java对内存映射的支持

FileChannel
代码示例:

public class DiskHelper {
    private final String fileName;
    private final long fileSize;
    private FileChannel fileChannel;
    private MappedByteBuffer mappedByteBuffer;

    public DiskHelper(final String fileName, final long fileSize) throws IOException {
        this.fileName = fileName;
        this.fileSize = fileSize;

        // 内存映射
        File file = new File(fileName);
        try {
            this.fileChannel = new RandomAccessFile(file, "rw").getChannel();
            this.mappedByteBuffer = this.fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileChannel != null) {
                this.fileChannel.close();
            }

        }
    }

    public byte[] read(long offset, int length) {
        ByteBuffer buffer = mappedByteBuffer.slice();
        buffer.position((int) offset);
        byte[] bytes = new byte[length];
        buffer.get(bytes);
        buffer.clear();
        return bytes;
    }

    public void write(byte[] bytes, long offset) {
        ByteBuffer buffer = mappedByteBuffer.slice();
        buffer.position((int) offset);
        buffer.put(bytes);
        mappedByteBuffer.force();
    }

    public void write(byte[] bytes, int offset, int length) {
        ByteBuffer buffer = mappedByteBuffer.slice();
        buffer.position(offset);
        buffer.put(bytes, 0, length);
        mappedByteBuffer.force();
    }

    public void shutdown() {
        try {
            if (fileChannel != null) {
                fileChannel.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

测试用例

public class DiskHelperTest {

    @Test
    public void testCreateReadWrite() throws IOException {
        DiskHelper diskHelper = new DiskHelper("test", 1024L * 1024);
        String test = "abcd";
        diskHelper.write(test.getBytes(StandardCharsets.UTF_8), 0L);

        byte[] content = diskHelper.read(0, 4);
        System.out.println(new String(content, StandardCharsets.UTF_8));
        diskHelper.shutdown();
    }
}

参考

  1. https://zh.wikipedia.org/wiki/%E5%86%85%E5%AD%98%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6
  2. 操作系统原理-内存映射文件 陈向群
目录
相关文章
|
2月前
|
存储 缓存 Linux
用户态内存映射
【9月更文挑战第20天】内存映射不仅包括物理与虚拟内存间的映射,还涉及将文件内容映射至虚拟内存,使得访问内存即可获取文件数据。mmap 系统调用支持将文件或匿名内存映射到进程的虚拟内存空间,通过多级页表机制实现高效地址转换,并利用 TLB 加速映射过程。TLB 作为页表缓存,存储频繁访问的页表项,显著提升了地址转换速度。
|
1月前
|
Linux C++
Linux c/c++文件虚拟内存映射
这篇文章介绍了在Linux环境下,如何使用虚拟内存映射技术来提高文件读写的速度,并通过C/C++代码示例展示了文件映射的整个流程。
46 0
|
1月前
|
程序员 Windows
程序员必备文件搜索工具 Everything 带安装包!!! 比windows自带的文件搜索快几百倍!!! 超级好用的文件搜索工具,仅几兆,不占内存,打开即用
文章推荐了程序员必备的文件搜索工具Everything,并提供了安装包下载链接,强调其比Windows自带搜索快且占用内存少。
43 0
|
2月前
|
存储 安全 Linux
将文件映射到内存,像数组一样访问
将文件映射到内存,像数组一样访问
29 0
|
2月前
|
消息中间件 Linux 容器
共享内存的创建和映射过程
【9月更文挑战第1天】消息队列、共享内存及信号量在使用前需生成key并获取唯一ID,均通过`xxxget`函数实现。
|
4月前
|
Java
jmap 查看jvm内存大小并进行dump文件内存分析
jmap 查看jvm内存大小并进行dump文件内存分析
92 3
|
5月前
|
Python
python3获取内存和cpu利用率记录日志文件psutil
python3获取内存和cpu利用率记录日志文件psutil
68 1
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0
|
5月前
|
监控 Linux
深入了解Linux的pmap命令:进程内存映射的利器
`pmap`是Linux下分析进程内存映射的工具,显示内存区域、权限、大小等信息。通过`/proc/[pid]/maps`获取数据,特点包括详细、实时和灵活。参数如`-x`显示扩展信息,`-d`显示设备。示例:`pmap -x 1234`查看进程1234的映射。注意权限、实时性和准确性。结合其他工具定期监控,排查内存问题。
有 3 个进程 P1、P2、P3 协作解决文件打印问题。P1 将文件记录从磁盘读入内存的缓冲区 1,每执行一次读一个记录 ;P2 将缓冲区 1 中的内容复制到缓冲区 2 中,每执行一次复制一个记录 ;
有 3 个进程 P1、P2、P3 协作解决文件打印问题。P1 将文件记录从磁盘读入内存的缓冲区 1,每执行一次读一个记录 ;P2 将缓冲区 1 中的内容复制到缓冲区 2 中,每执行一次复制一个记录 ;