原文地址:http://blog.csdn.net/joejames/article/details/37958017

一直都对内存映射文件这个概念很模糊,不知道它和虚拟内存有什么区别,而且映射这个词也很让人迷茫,今天终于搞清楚了。。。下面,我先解释一下我对映射这个词的理解,再区分一下几个容易混淆的概念,之后,什么是内存映射就很明朗了。

原理

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

图1.内存映射原理

既然建立内存映射没有进行实际的数据拷贝,那么进程又怎么能最终直接通过内存操作访问到硬盘上的文件呢?那就要看内存映射之后的几个相关的过程了。

mmap()会返回一个指针ptr,它指向进程逻辑地址空间中的一个地址,这样以后,进程无需再调用read或write对文件进行读写,而只需要通过ptr就能够操作文件。但是ptr所指向的是一个逻辑地址,要操作其中的数据,必须通过MMU将逻辑地址转换成物理地址,如图1中过程2所示。这个过程与内存映射无关。

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

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

效率

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

图2.read系统调用原理

下面这个程序,通过read和mmap两种方法分别对硬盘上一个名为“mmap_test”的文件进行操作,文件中存有10000个整数,程序两次使用不同的方法将它们读出,加1,再写回硬盘。通过对比可以看出,read消耗的时间将近是mmap的两到三倍

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/time.h>
#include<fcntl.h>
#include<sys/mman.h>#define MAX 10000int main()
{
int i=0;
int count=0, fd=0;
struct timeval tv1, tv2;
int *array = (int *)malloc( sizeof(int)*MAX );/*read*/gettimeofday( &tv1, NULL );
fd = open( "mmap_test", O_RDWR );
if( sizeof(int)*MAX != read( fd, (void *)array, sizeof(int)*MAX ) )
{
printf( "Reading data failed.../n" );
return -1;
}
for( i=0; i<MAX; ++i )++array[ i ];
if( sizeof(int)*MAX != write( fd, (void *)array, sizeof(int)*MAX ) )
{
printf( "Writing data failed.../n" );
return -1;
}
free( array );
close( fd );
gettimeofday( &tv2, NULL );
printf( "Time of read/write: %dms/n", tv2.tv_usec-tv1.tv_usec );/*mmap*/gettimeofday( &tv1, NULL );
fd = open( "mmap_test", O_RDWR );
array = mmap( NULL, sizeof(int)*MAX, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );
for( i=0; i<MAX; ++i )++array[ i ];
munmap( array, sizeof(int)*MAX );
msync( array, sizeof(int)*MAX, MS_SYNC );
free( array );
close( fd );
gettimeofday( &tv2, NULL );
printf( "Time of mmap: %dms/n", tv2.tv_usec-tv1.tv_usec );return 0;
}

输出结果:

Time of read/write: 154ms

Time of mmap: 68ms

Linux内存映射mmp机制详解相关推荐

  1. Linux Jump Label/static-key机制详解

    Linux Jump Label/static-key机制详解 RToax 2021年3 关于Linux Jump Label(x86)已经进行过概述,下面就static-key进行详述. 内核中有很 ...

  2. Linux内存管理之mmap详解

    一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进内存.文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零.munmap执行相 ...

  3. linux内核rcu,linux内核rcu机制详解

    RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制读取数 ...

  4. Linux(Ubuntu)内存查询top命令详解

    linux中的top命令详解 引言 top命令是UNIX/Linux系统中,用于查看系统详情的第一入口,一般我们查看机器运行状态的时候,总是第一个使用top命令,而实际上top命令展示的数据很多,对于 ...

  5. python内存的回收机制_python的内存管理和垃圾回收机制详解

    简单来说python的内存管理机制有三种 1)引用计数 2)垃圾回收 3)内存池 接下来我们来详细讲解这三种管理机制 1,引用计数: 引用计数是一种非常高效的内存管理手段,当一个pyhton对象被引用 ...

  6. ptmalloc内存分配和回收详解(文字版)

    ptmalloc内存分配和回收详解(文字版) 进程默认内存布局(x86) 从进程的内存布局可知,.bss段之上的这块分配给用户程序的空间被称之为heap,start_brk指向heap的开始,而brk ...

  7. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入Lin ...

  8. Binder机制详解(一)

    系列目录 Binder机制详解(二) Binder机制详解(三) 文章目录 前言 一.爱情例子 1.普通Linux间进程通信方式 2.接着讲爱情的例子(Binder的实现机制) 3.Binder少拷贝 ...

  9. python语言程序的特点_Python语言概述及其运行机制详解

    即日起,我们将打开一个新的编程世界的大门--Python语言.Python是一种跨平台的计算机程序设计语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新 ...

最新文章

  1. 云计算推进企业管理深化,私有云将会深入企业
  2. java浏览器实验报告_关于java实验报告模板
  3. [Android]ListView控件之Adapter性能优化
  4. django-python3-mysql问题
  5. 数据查询和业务流分开_TiDB HTAP 助力小红书业务升级
  6. LeedCode刷题
  7. AtomicInteger 的使用
  8. 使用C#,轻松发邮件之QQ邮箱
  9. linux实训4文件系统管理,实训项目4 文件系统管理.docx
  10. java银行叫号_银行排队叫号系统
  11. 金角大王 python_【51CTO学院三周年】 老男孩python全栈心路
  12. Android进阶之路(快速进阶第二天)RxAndroid使用
  13. 输入一个数,分别输出个位,十位,百位
  14. Cause: org.postgresql.util.PSQLException: 错误: 对于可变字符类型来说,值太长了(255)
  15. 【Motif Discovery with Missing Data】
  16. 快应用开发:开发基础
  17. python将图片转矩阵
  18. 喇叭、扬声器的正负极问题
  19. 从安卓巴士到CocoaChina,曾经的顶级流量王者,如今的落寞与淡去
  20. 企业即时通讯软件Cnskype for Business

热门文章

  1. (十六)Alian 的 Spring Cloud Eureka 集群配置(主机名方式)
  2. 图解:什么是关键路径?
  3. [附源码]Python计算机毕业设计Django保护濒危动物公益网站
  4. GO语言的sdk下载安装和配置
  5. 5 个最佳网络模拟器:Cisco Packet Tracer、Boson NetSim、GNS3、VIRL、EVE-NG
  6. UCML异常提示:无效URI
  7. 985研究生嫖娼被开除,起诉学校一审被驳回,当事人称将上诉!
  8. '963c705a8a4135a3bc70e72a6ec43c39' /堡垒之夜
  9. (427)Java分支结构 循环结构
  10. java版小易准备去魔法王国采购魔法神器