http://blog.csdn.net/kongdefei5000/article/details/70183119

内存映射是个很有用,也很有意思的思想。我们都知道操作系统分为用户态和内核态,用户态是不能直接和物理设备打交道的,如果想把硬盘的一块区域读到用户态,则需要两次拷贝(硬盘->内核->用户),但是内存映射的设计只需要发生一次的拷贝,大大的提高了读取数据的效率。那么内存映射的原理和内核是如何实现的呢?

因为内存映射涉及到虚拟内存的管理,虚拟内存到物理内存的映射,因此在详细介绍内存映射前先普及(回忆)一下相关的概念。

CPU的架构

目前CPU架构主要分为三种:SMP, NUMA, MPP,详细的介绍参考CPU架构。这里主要关注MMU和TLB在CPU中的角色和位置。 
 
上图是Intel的i7处理器一个核的架构图,图中可以看出每一个CPU核都已一个自己的MMU和TLB。

Linux进程和线程

关于Linux进程和线程的话题想必大家都不陌生,这也是面试时候经常被问到的问题,后续我会专门写一篇博文介绍Linux线程和进程的区别,已经内核是如何实现的。这里我们只需要知道下面几个概念即可: 
* 操作系统本身也是一个进程 
* 操作系统内核层面没有线程的概念,只有进程的概念,因此线程在内核看来也是一个进程,只是比较特殊 
* 线程的实现是glibc实现的(pthread),包括创建,管理等

虚拟地址

虚拟地址是面向进程的一套虚拟内存的地址,为了更好的管理内存,并且能够保证内存对程序员而言是透明的,也就是写程序的时候对每一个程序来说都是一样的地址空间,因此提出了虚拟内存的概念,对应的就是虚拟地址。这里我们不关注具体的细节,为了后面的讲解,我们简单的了解一下虚拟内存在内核层面是怎么进行管理的。 

这张图右侧的进程虚拟器对于每一个进程都是一样的,就是上面说的虚拟空间,然后对于进程,内核对每一个进程都维护了一个task_struch的结构,其中有三个重要的成员,pgd指向改进程的页表首地址,然后mmap和mm_rb都是用来管理vm的结构,vm是虚拟内存管理的基本单元,含有内存的类型,起始和结束地址,mmap是线性表实现的,mm_rb则使用红黑树进行管理,分别适用不同的场景。

MMU

MMU(Memory Management Unit),内存管理单元,主要负责CPU内存访问的时候将虚拟地址转换为物理地址的单元。也就是说CPU想要访问内存必须先经过MMU的转换,获得真正的物理地址,才能读写物理内存的数据。其实MMU只是一个简单的计算单元,它通过虚拟地址查找页表,找到对应的物理地址,然后返回给CPU。在查找页表的过程中可能发生多次的物理内存访问,这取决于系统采用页表管理系统是几级的,目前Linux的页表是四级的,因此需要查询四次页表,每一次查询都会获得一个物理地址指向下一级页表的内存地址,知道最后获得实际要访问的内存物理地址。 
 
从图中可以看出,当CPU得到一个虚拟地址去访问内存的时候会先将虚拟地址发送到MMU(1),然后MMU会先从TLB查询是否存在这个虚拟地址到物理地址的缓存,如果存在则直接返回给CPU,如果没有则会根据虚拟地址讲过计算获得物理内存中页表项的地址然后读取得到PTE(Linux可能要读取四次),PTE就是物理内存地址或者硬盘存储地址。然后MMU会将该PTE缓存在TLB中,最后使用这个物理地址再次访问物理内存或者硬盘地址获得要访问的内容。

内存映射

mmap

基础知识介绍完毕,那么到底什么是内存映射呢,映射让我们不禁都会想起数学上的映射关系,是的就是那个意思,这里是讲设备或者硬盘存储的一块空间映射到物理内存,然后操作这块物理内存就是在操作实际的硬盘空间,不需要经过内核态传递。比如你的硬盘上有一个文件,你可以使用linux系统提供的mmap接口,讲这个文件映射到进程一块虚拟地址空间,这块空间会对应一块物理内存,当你读写这块物理空间的时候,就是在读取实际的磁盘文件,就是这么直接,这么高效。通常诸如共享库的加载都是通过内存映射的方式加载到物理内存的。

mmap本身其实是一个很简单的操作,在进程的页表中添加一个页表项,该页表项是物理内存的地址。调用mmap的时候,内核会在改进程的虚拟空间的映射区域查找一块满足需求的空间用于映射该文件,然后生成该虚拟地址的页表项,改页表项此时的有效位(标志是否已经在物理内存中)为0,页表项的内容是文件的磁盘地址,此时mmap的任务已经完成。 
 
当mmap建立完页表的映射后,就可以操作改块内存了,进行的所有改动都会自动写会磁盘文件。第一次访问该块内存的时候,因为页表项的有效位还是0,就会发生缺页中断,然后CPU会使用该页表项的内容也就是磁盘的文件地址,讲该地址指向的内容加载到物理内存,并需改页表项的内容为该物理地址,有效位置为1. 

munmap

有映射必然有解除映射,系统提供了一个munmap的接口去解除指定地址的映射关系。munmap主要的功能是清除页表项,解除这个映射关系,但是这个过程中会涉及到缓存的刷新,虚拟内存vm的删除,TLB的一致性(tlb shootdown操作),这里就不再详细讲解。

附件:内存映射

原文地址:http://kdf5000.com/2017/02/17/mmap内存映射/

mmap内存映射的更多相关文章

  1. linux mmap 内存映射【转】

    转自:http://blog.csdn.net/xyyangkun/article/details/7830313 [-] mmap vs readwritelseek mmap vs malloc ...

  2. 【转】Python之mmap内存映射模块(大文本处理)说明

    [转]Python之mmap内存映射模块(大文本处理)说明 背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力 ...

  3. linux mmap 内存映射

    mmap() vs read()/write()/lseek() 通过strace统计系统调用的时候,经常可以看到mmap()与mmap2().系统调用mmap()可以将某文件映射至内存(进程空间), ...

  4. sendfile“零拷贝”和mmap内存映射

    在学习sendfille之前,我们先来了解一下浏览器访问页面时,后台服务器的大致工作流程. 下图是从用户访问某个页面到页面的显示这几秒钟的时间当中,在后台的整个工作过程. 如上图,黑色箭头所示的过程, ...

  5. Python之mmap内存映射模块(大文本处理)说明

    背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力.关于sed的说明可以看了解sed的工作原理,本文将介绍通过 ...

  6. mmap内存映射复习

    c语言初学时,比较常见的一个习题就是实现cp. 使用c库实现的cp就不赘述了. 最近工作用到内存映射,就拿来练下手,复习一下mmap的用法. 很简单,将目标文件和源文件映射到内存,然后使用memcpy ...

  7. [转载]Linux驱动mmap内存映射

    原文地址:https://www.cnblogs.com/wanghuaijun/p/7624564.html mmap在linux哪里? 什么是mmap? 上图说了,mmap是操作这些设备的一种方法 ...

  8. Linux驱动mmap内存映射

    mmap在linux哪里? 什么是mmap? 上图说了,mmap是操作这些设备的一种方法,所谓操作设备,比如IO端口(点亮一个LED).LCD控制器.磁盘控制器,实际上就是往设备的物理地址读写数据. ...

  9. 共享内存之——mmap内存映射

    共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件 (特殊情况下还可以采用匿名映射)机制实现,也可以通过sy ...

随机推荐

  1. Java高级工程师应该掌握的东东

    今天偶然看了膜拜单车官网对java程序员的招聘要求,如下,可以对照发现自己的不足 职责 负责APP SERVER中间层等模块开发 完成各类需求开发任务,同时保证服务稳定性.茁壮性 要求 精通Java语 ...

  2. python3 发送邮件添加附件

    from email.header import Headerfrom email.mime.application import MIMEApplicationfrom email.mime.mul ...

  3. about rand and reflect

    select regexp_replace(reflect("java.util.UUID", "randomUUID"), "-", &q ...

  4. 5-----BBS论坛

    BBS论坛(五) 5.1.cms后台修改密码功能完成 (1)新建app/forms.py # app/forms.py from wtforms import Form class BaseForm( ...

  5. python17 多线程学习

    多线程 多任务可以由多进程完成,也可以由一个进程内的多线程完成. 我们前面提到了进程是由若干线程组成的,一个进程至少有一个线程. 由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的 ...

  6. VIM操作手札

    查看帮助手册 [Vim 中文帮助文档] 常用命令及说明 在命令模式下编辑 命令 说明 Ctrl+u 向文件首翻半屏 Ctrl+d 向文件尾翻半屏 Ctrl+f 向文件尾翻一屏 Ctrl+b 向文件首翻 ...

  7. mysql 死锁解决办法

    查询表的时候,发现一圈圈转啊转,就是不出来数据,猜测表被锁住 解决办法 : mysql> show processlist ; mysql> kill 4;       说明 : 4为 i ...

  8. 未来HTML6出现的10个特性

    网络技术正趋向于发展为一个巨大的移动APP市场,在Web开发的革命浪潮中起着指示性作用,自HTML引入以来,创建可转换,有新意的网络移动应用程序变得So easy,web开发中运用先进技术也很容易处理 ...

  9. PopUpWindow使用方法

    个人使用建议,容易犯错:先设置属性再显示,而不是先出来了,再设置都没用了,显示一般是用showatlocation,或者showasdropdown 个人建议2:popupWindow的显示的两个方法 ...

  10. Murano Weekly Meeting 2015.07.28

    Meeting time: 2015.July.28th 1:00~2:00 Chairperson: Kirill Zaitsev, core from Mirantis Meeting summa ...