内存映射文件原理探索

首先说说这篇文章要解决什么问题?

1.虚拟内存与内存映射文件的区别与联系.

2.内存映射文件的原理.

3.内存映射文件的效率.

4.传统IO和内存映射效率对比.

虚拟内存与内存映射文件的区别与联系

 二者的联系

虚拟内存和内存映射文件都是将一部分内容加载到,另一部分放在磁盘上的一种机制,二者都是应用程序动态性的基础,由于二者的虚拟性,对于用户都是透明的.

虚拟内存其实就是硬盘的一部分,是计算机RAM与硬盘的数据交换区,因为实际的物理内存可能远小于进程的地址空间,这就需要把内存中暂时不用到的数据放到硬盘上一个特殊的地方,当请求的数据不在内存中时,系统产生却页中断,内存管理器便将对应的内存页重新从硬盘调入物理内存。

内存映射文件是由一个文件到一块内存的映射,使应用程序可以通过内存指针对磁盘上的文件进行访问,其过程就如同对加载了文件的内存的访问,因此内存文件映射非常适合于用来管理大文件。

二者的区别

1.虚拟内存使用硬盘只能是页面文件,而内存映射使用的磁盘部分可以是任何磁盘文件.

2.二者的架构不同,或者是说应用的场景不同,虚拟内存是架构在物理内存之上,其引入是因为实际的物理内存运行程序所需的空间,即使现在计算机中的物理内存越来越大,程序的尺寸也在增长。将所有运行着的程序全部加载到内存中不经济也非常不现实。内存映射文件架构在程序的地址空间之上,32位机地址空间只有4G,而某些大文件的尺寸可要要远超出这个值,因此,用地址空间中的某段应用文件中的一部分可解决处理大文件的问题,在32中,使用内存映射文件可以处理2的64次(64EB)大小的文件.原因内存映射文件,除了处理大文件,还可用作进程间通信。

内存映射文件的原理

“映射”就是建立一种对应关系,在这里主要是指硬盘上文件的位置与进程逻辑地址空间中一块相同区域之间一一对应,这种关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在的,在内存映射过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上放入了内存,具体到代码,就是建立并初始化了相关的数据结构,这个过程有系统调用mmap()实现,所以映射的效率很高.

                     内存映射原理

上面说到建立内存映射没有进行实际的数据拷贝,那么进行进程又怎么能最终通过内存操作访问到硬盘上的文件呢?

看上图:

1.调用mmap(),相当于要给进行内存映射的文件分配了虚拟内存,它会返回一个指针ptr,这个ptr所指向的是一个逻辑地址,要操作其中的数据,必须通过MMU将逻辑地址转换成物理地址,如图1中过程2所示。

2.建立内存映射并没有实际拷贝数据,这时,MMU在地址映射表中是无法找到与ptr相对应的物理地址的,也就是MMU失败,将产生一个缺页中断,缺 页中断的中断响应函数会在swap中寻找相对应的页面,如果找不到(也就是该文件从来没有被读入内存的情况),则会通过mmap()建立的映射关系,从硬 盘上将文件读取到物理内存中,如图1中过程3所示。

3.如果在拷贝数据时,发现物理内存不够用,则会通过虚拟内存机制(swap)将暂时不用的物理页面交换到硬盘上,如图1中过程4所示。

内存映射文件的效率

了解过内存映射文件都知道,它比传统的IO读写数据快很多,那么,它为什么会这么快,从代码层面上来看,从硬盘上将文件读入内存,都是要经过数据拷贝,并且数据拷贝操作是由文件系统和硬件驱动实现的,理论上来说,拷贝数据的效率是一 样的。其实,原因是read()是系统调用,其中进行了数据 拷贝,它首先将文件内容从硬盘拷贝到内核空间的一个缓冲区,如图2中过程1,然后再将这些数据拷贝到用户空间,如图2中过程2,在这个过程中,实际上完成 了两次数据拷贝 ;而mmap()也是系统调用,如前所述,mmap()中没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,只进行了 一次数据拷贝 。因此,内存映射的效率要比read/write效率高。

                                    read系统调用原理

 传统IO和内存映射效率对比.

在这里,使用java传统的IO,加缓冲区的IO,内存映射分别读取10M数据.用时如下:

public class MapBufDelete {
    public static void main(String[] args) {
        try {
            FileInputStream fis=new FileInputStream("./largeFile.txt");
            int sum=0;
            int n;
            long t1=System.currentTimeMillis();
            try {
                while((n=fis.read())>=0){
                    //  数据处理
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            long t=System.currentTimeMillis()-t1;
            System.out.println("传统IOread文件,不使用缓冲区,用时:"+t);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        try {
            FileInputStream fis=new FileInputStream("./largeFile.txt");
            BufferedInputStream bis=new BufferedInputStream(fis);
            int sum=0;
            int n;
            long t1=System.currentTimeMillis();
            try {
                while((n=bis.read())>=0){
                  //  数据处理
                }
            } catch (IOException e) {

                e.printStackTrace();
            }
            long t=System.currentTimeMillis()-t1;
            System.out.println("传统IOread文件,使用缓冲区,用时:"+t);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        MappedByteBuffer buffer=null;
        try {
            buffer=new RandomAccessFile("./largeFile.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);
            int sum=0;
            int n;
            long t1=System.currentTimeMillis();
            for(int i=0;i<1024*1024*10;i++){
                //  数据处理
            }
            long t=System.currentTimeMillis()-t1;
            System.out.println("内存映射文件读取文件,用时:"+t);
        } catch (FileNotFoundException e) {

            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
        }

    }
}

运行结果

传统IOread文件,不使用缓冲区,用时:4739
传统IOread文件,使用缓冲区,用时:59
内存映射文件读取文件,用时:11

最后,解释一下,为什么使用缓冲区读取文件会比不使用快:

原因是每次进行IO操作,都要从用户态陷入内核态,由内核把数据从磁盘中读到内核缓冲区,再由内核缓冲区到用户缓冲区,如果没有buffer,读取都需要从用户态到内核态切换,而这种切换很耗时,所以,采用预读,减少IO次数,如果有buffer,根据局部性原理,就会一次多读数据,放到缓冲区中,减少了IO次数.

时间: 2024-10-16 19:51:27

内存映射文件原理探索的相关文章

内存映射文件原理探索(转载)

转载:http://blog.chinaunix.net/uid-20761674-id-3072683.html 一直都对内存映射文件这个概念很模糊,不知道它和虚拟内存有什么区别,而且映射这个词也很让人迷茫,今天终于搞清楚了...下面,我先解释一下我对映射这个词的理解,再区分一下几个容易混淆的概念,之后,什么是内存映射就很明朗了. 原理 首先,"映射"这个词,就和数学课上说的"一一映射"是一个意思,就是建立一种一一对应关系,在这里主要是只 硬盘上文件 的位置与进程

内存映射文件原理探索(转)

一直都对内存映射文件这个概念很模糊,不知道它和虚拟内存有什么区别,而且映射这个词也很让人迷茫,今天终于搞清楚了...下面,我先解释一下我对映射这个词的理解,再区分一下几个容易混淆的概念,之后,什么是内存映射就很明朗了. 原理 首先,“映射”这个词,就和数学课上说的“一一映射”是一个意思,就是建立一种一一对应关系,在这里主要是只 硬盘上文件 的位置与进程 逻辑地址空间 中一块大小相同的区域之间的一一对应,如图1中过程1所示.这种对应关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间

JAVA NIO之浅谈内存映射文件原理与DirectMemory

Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原理. 在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数  read().write() ,此时调用此函数的进程(在JAVA中即java进程)由当前的用户态切换到内核态,然后OS的内核代码负责将相应的文件数据读取到内核的IO缓冲区,然后再把数据从内核IO缓冲区拷贝到进程的私有

NIO之内存映射文件原理

原文链接:https://www.cnblogs.com/lyftest/p/6564547.html Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原理. 在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数  read().write() ,此时调用此函数的进程(在JAVA中即java进程)由当前的用户态切换到内核态,然

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转

原文:C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当.实际上,任何想要共享数据的通信模型都会在幕后使用它. 内存映射文件究竟是个什么?内存映射文件允许你保留一块地址空间,然后将该物理存储映射到这块内存空间中进行操作.物理存储是文件管理,而内存

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当.实际上,任何想要共享数据的通信模型都会在幕后使用它. 内存映射文件究竟是个什么?内存映射文件允许你保留一块地址空间,然后将该物理存储映射到这块内存空间中进行操作.物理存储是文件管理,而内存映射文件是操作系统级内存管理. 优势:     1.访问磁盘文件上的数据不需执行I/O操作和缓存

计算机程序的思维逻辑 (61) - 内存映射文件及其应用 - 实现一个简单的消息队列

本节介绍内存映射文件,内存映射文件不是Java引入的概念,而是操作系统提供的一种功能,大部分操作系统都支持. 我们先来介绍内存映射文件的基本概念,它是什么,能解决什么问题,然后我们介绍如何在Java中使用,我们会设计和实现一个简单的.持久化的.跨程序的消息队列来演示内存映射文件的应用. 基本概念 所谓内存映射文件,就是将文件映射到内存,文件对应于内存中的一个字节数组,对文件的操作变为对这个字节数组的操作,而字节数组的操作直接映射到文件上.这种映射可以是映射文件全部区域,也可以是只映射一部分区域.

NET 4 中 内存映射文件

原文链接 : http://blogs.msdn.com/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx 预备知识 : 本文需要你对 OS 内存管理有一定了解. 我想探索下即将到来的 .NET 4 中一些与众不同的新特性,而不是已被大众所熟知的动态类型.协变与逆变等特性.出于对性能增强的喜爱,接下来俺将发表几篇新特性的博文. 内存映射文件对于托管世界的开发人员来说,似乎就像是火星人一样陌生

(转)虚拟内存与内存映射文件区别与联系

虚拟内存与内存映射文件是操作系统内存管理的重要部分,二者有相似也有不同的地方,本文是作者学习与应用中得到的一些体会,有错误的地方,请提点. 二者的联系:虚拟内存与内存映射文件都是将一部分内容加载的内存,另一部分放在磁盘(硬盘)上的一种机制.二者都是应用程序动态性的基础.由于二者的虚拟性,对于应用而言,都是透明的. 学过操作系统的都知道虚拟内存其实就是磁盘的一部分,是计算机RAM与硬盘的数据交换区.因为实际的物理内存可能远小于进程的地址空间,这就需要把内存中暂时不用到的数据放到硬盘上一个特殊的地方