http://blog.csdn.net/edwardlulinux/article/details/8604400

很多文章分析了mmap的实现原理。从代码的逻辑来分析,总是觉没有把mmap后读写映射区域和普通的read/write联系起来。不得不产生疑问:

1,普通的read/write和mmap后的映射区域的读写到底有什么区别。

2, 为什么有时候会选择mmap而放弃普通的read/write。

3,如果文章中的内容有不对是或者是不妥的地方,欢迎大家指正。

围绕着这两个问题分析一下,其实在考虑这些问题的同时不免和其他的很多系统机制产生交互。虽然是讲解mmap,但是很多知识还是为了阐明问题做必要的铺垫。这些知识也正是linux的繁琐所在。一个应用往往和系统中的多种机制交互。这篇文章中尽量减少对源代码的引用和分析。把这样的工作留到以后的细节分析中。但是很多分析的理论依据还是来自于源代码。可见源代码的重要地位。

基础知识:

1, 进程每次切换后,都会在tlb base寄存器中重新load属于每一个进程自己的地址转换基地址。在cpu当前运行的进程中都会有current宏来表示当前的进程的信息。应为这个代码实现涉及到硬件架构的问题,为了避免差异的存在在文章中用到硬件知识的时候还是指明是x86的架构,毕竟x86的资料和分析的研究人员也比较多。其实arm还有其他类似的RISC的芯片,只要有mmu支持的,都会有类似的基地址寄存器。

2, 在系统运行进程之前都会为每一个进程分配属于它自己的运行空间。并且这个空间的有效性依赖于tlb base中的内容。32位的系统中访问的空间大小为4G。在这个空间中进程是“自由”的。所谓“自由”不是说对于4G的任何一个地址或者一段空间都可以访问。如果要访问,还是要遵循地址有效性,就是tlb base中所指向的任何页表转换后的物理地址。其中的有效性有越界,权限等等检查。

3, 任何一个用户进程的运行在系统分配的空间中。这个空间可以有

vma:struct vm_area_struct来表示。所有的运行空间可以有这个结构体描述。用户进程可以分为text data 段。这些段的具体在4G中的位置有不同的vma来描述。Vma的管理又有其他机制保证,这些机制涉及到了算法和物理内存管理等。请看一下两个图片:

图 一:

图 二:

系统调用中的write和read:

这里没有指定确切的文件系统类型作为分析的对象。找到系统调用号,然后确定具体的文件系统所带的file operation。在特定的file operation中有属于每一种文件系统自己的操作函数集合。其中就有read和write。

图 三:

在真正的把用户数据读写到磁盘或者是存储设备前,内核还会在page cache中管理这些数据。这些page的存在有效的管理了用户数据和读写的效率。用户数据不是直接来自于应用层,读(read)或者是写入(write)磁盘和存储介质,而是被一层一层的应用所划分,在每一层次中都会有不同的功能对应。最后发生交互时,在最恰当的时机触发磁盘的操作。通过IO驱动写入磁盘和存储介质。这里主要强调page cache的管理。应为page的管理设计到了缓存,这些缓存以page的单位管理。在没有IO操作之前,暂时存放在系统空间中,而并未直接写入磁盘或者存贮介质。

系统调用中的mmap:

当创建一个或者切换一个进程的同时,会把属于这个当前进程的系统信息载入。这些系统信息中包含了当前进程的运行空间。当用户程序调用mmap后。函数会在当前进程的空间中找到适合的vma来描述自己将要映射的区域。这个区域的作用就是将mmap函数中文件描述符所指向的具体文件中内容映射过来。

原理是:mmap的执行,仅仅是在内核中建立了文件与虚拟内存空间的对应关系。用户访问这些虚拟内存空间时,页面表里面是没有这些空间的表项的。当用户程序试图访问这些映射的空间时,于是产生缺页异常。内核捕捉这些异常,逐渐将文件载入。所谓的载入过程,具体的操作就是read和write在管理pagecache。Vma的结构体中有很文件操作集。vma操作集中会有自己关于page cache的操作集合。这样,虽然是两种不同的系统调用,由于操作和调用触发的路径不同。但是最后还是落实到了page cache的管理。实现了文件内容的操作。

Ps:

文件的page cache管理也是很好的内容。涉及到了address space的操作。其中很多的内容和文件操作相关。

效率对比:

这里应用了网上一篇文章。发现较好的分析,着这里引用一下。

Mmap:

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <sys/mman.h>

void main()

{

int fd = open("test.file", 0);

struct stat statbuf;

char *start;

char buf[2] = {0};

int ret = 0;

fstat(fd, &statbuf);

start = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

do {

*buf = start[ret++];

}while(ret < statbuf.st_size);

}

Read:

#include <stdio.h>

#include <stdlib.h>

void main()

{

FILE *pf = fopen("test.file", "r");

char buf[2] = {0};

int ret = 0;

do {

ret = fread(buf, 1, 1, pf);

}while(ret);

}

运行结果:

[xiangy@compiling-server test_read]$ time ./fread

real    0m0.901s

user    0m0.892s

sys     0m0.010s

[xiangy@compiling-server test_read]$ time ./mmap

real    0m0.112s

user    0m0.106s

sys     0m0.006s

[xiangy@compiling-server test_read]$ time ./read

real    0m15.549s

user    0m3.933s

sys     0m11.566s

[xiangy@compiling-server test_read]$ ll test.file

-rw-r--r-- 1 xiangy svx8004 23955531 Sep 24 17:17 test.file

可以看出使用mmap后发现,系统调用所消耗的时间远远比普通的read少很多

Mmap的实现原理和应用的更多相关文章

  1. 认真分析mmap:是什么 为什么 怎么用

    mmap基础概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.实现这样的映射关系后,进程就可以采用指 ...

  2. 认真分析mmap:是什么 为什么 怎么用【转】

    转自:http://www.cnblogs.com/huxiao-tee/p/4660352.html?utm_source=tuicool&utm_medium=referral 阅读目录 ...

  3. 磁盘文件I/O,SSD结构,局部性原理 笔记

    磁盘文件I/O过程 进程向内核发起read scene.dat请求: 内核根据inode获取对应该进程的address space,在address space查找page_cache,如果没有找到, ...

  4. Java网络编程和NIO详解8:浅析mmap和Direct Buffer

    Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...

  5. Linux下多任务间通信和同步-mmap共享内存

    Linux下多任务间通信和同步-mmap共享内存 嵌入式开发交流群280352802,欢迎加入! 1.简介 共享内存可以说是最有用的进程间通信方式.两个不用的进程共享内存的意思是:同一块物理内存被映射 ...

  6. libtool的工作原理

    libtool 是一个通用库支持脚本,将使用动态库的复杂性隐藏在统一.可移植的接口中:使用libtool的标准方法,可以在不同平台上创建并调用动态库.可以认为libtool是gcc的一个抽象,其包装了 ...

  7. Java网络编程与NIO详解8:浅析mmap和Direct Buffer

    微信公众号[黄小斜]作者是蚂蚁金服 JAVA 工程师,目前在蚂蚁财富负责后端开发工作,专注于 JAVA 后端技术栈,同时也懂点投资理财,坚持学习和写作,用大厂程序员的视角解读技术与互联网,我的世界里不 ...

  8. Android mmap 文件映射到内存介绍

    本文链接: Android mmap 文件映射到内存介绍 Android开发中,我们可能需要记录一些文件.例如记录log文件.如果使用流来写文件,频繁操作文件io可能会引起性能问题. 为了降低写文件的 ...

  9. 认真分析mmap:是什么 为什么 怎么用(转)

    阅读目录 mmap基础概念 mmap内存映射原理 mmap和常规文件操作的区别 mmap优点总结 mmap相关函数 mmap使用细节 回到顶部 mmap基础概念 mmap是一种内存映射文件的方法,即将 ...

随机推荐

  1. .NET开发作业调度(job scheduling) - Quartz.NET

    Quartz.NET是JAVA Job Scheduling框架Quartz在.NET平台上的实现,可以满足小型乃至大型企业应用中的Job Scheduling. 通过Nuget安装Quartz.NE ...

  2. Oracle中的注释

    注释用于对程序代码的解释说明,它能够增强程序的可读性,是程序易于理解. 单行注释: 用“--”,后面跟上注释的内容 Declare Num_sal number; --声明一个数字类型的变量 Var_ ...

  3. virtualbox centos安装增强工具

    系统的,VBoxLinuxAdditions-amd64.run 是用于64位系统的.执行以下命令来安装sh ./VBoxLinuxAdditions-x86.run 5.安装成功后重启系统.

  4. IOS开发经验分享

    一些IOS开发的心得: 1) [Multiple Threads] IOS多线程注意, 所有的UI操作都必须在主线程上: Any code that will update the UI should ...

  5. html笔记 仅适用于个人

    如何使图片与文本框上下对齐 其实就给<img>加一个属性 align="absmiddle" <form method="post" acti ...

  6. Notes of the scrum meeting(10/30)

    meeting time:9:30~11:30p.m.,October 29th,2013 meeting place:20公寓楼前 attendees: 顾育豪                    ...

  7. 给同一个表中的两个外键写sql

    一个表有两个外键都指向另一个表的主键时,如何检索他们的数据? 例如,表TableA有两个列,puserID和friendID. 表TableB有两个列,userID和userName. 我们怎样检索数 ...

  8. js异步加载 defer和async 比较

    网上说法很多,很少一句话能总结清楚的,终于找到两句一针见血的描述,很到位: 相同点:都不阻塞DOM解析 defer  :顺序:保证先后顺序.解析:HTML 解析器遇到它们时,不阻塞(脚本将被异步下载) ...

  9. Microsoft SQLServer有四种系统数据库

    Microsoft SQLServer有四种系统数据库: 1.master数据库 master数据库记录SQLServer系统的所有系统级别信息.它记录所有的登录帐户和系统配置设置.master数据库 ...

  10. Eclipse plugin插件开发 NoClassDefFoundError

    Eclipse的每一个plugin都有属于自己的类加载器,这是OSGI架构的基础,每一个plugin项目都是一个bundle,独立运行在各自的运行环境里面,这就造成了开发时和运行时的不同. Eclip ...