mmap内存映射
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内存映射的更多相关文章
- linux mmap 内存映射【转】
转自:http://blog.csdn.net/xyyangkun/article/details/7830313 [-] mmap vs readwritelseek mmap vs malloc ...
- 【转】Python之mmap内存映射模块(大文本处理)说明
[转]Python之mmap内存映射模块(大文本处理)说明 背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力 ...
- linux mmap 内存映射
mmap() vs read()/write()/lseek() 通过strace统计系统调用的时候,经常可以看到mmap()与mmap2().系统调用mmap()可以将某文件映射至内存(进程空间), ...
- sendfile“零拷贝”和mmap内存映射
在学习sendfille之前,我们先来了解一下浏览器访问页面时,后台服务器的大致工作流程. 下图是从用户访问某个页面到页面的显示这几秒钟的时间当中,在后台的整个工作过程. 如上图,黑色箭头所示的过程, ...
- Python之mmap内存映射模块(大文本处理)说明
背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力.关于sed的说明可以看了解sed的工作原理,本文将介绍通过 ...
- mmap内存映射复习
c语言初学时,比较常见的一个习题就是实现cp. 使用c库实现的cp就不赘述了. 最近工作用到内存映射,就拿来练下手,复习一下mmap的用法. 很简单,将目标文件和源文件映射到内存,然后使用memcpy ...
- [转载]Linux驱动mmap内存映射
原文地址:https://www.cnblogs.com/wanghuaijun/p/7624564.html mmap在linux哪里? 什么是mmap? 上图说了,mmap是操作这些设备的一种方法 ...
- Linux驱动mmap内存映射
mmap在linux哪里? 什么是mmap? 上图说了,mmap是操作这些设备的一种方法,所谓操作设备,比如IO端口(点亮一个LED).LCD控制器.磁盘控制器,实际上就是往设备的物理地址读写数据. ...
- 共享内存之——mmap内存映射
共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件 (特殊情况下还可以采用匿名映射)机制实现,也可以通过sy ...
随机推荐
- tomcat的安装部署
第一步: 先把压缩包拖到知道的目录,解压 tar xf apache-tomcat-8.0.27.tar.gz -C /usr/local/ ln -s /usr/local/apache-tomca ...
- Jenkins安全配置详解
一.进入安全配置界面 首页后点击进入系统管理(Manage Jenkins) ——下拉下方看到安全配置(Configure Global Security) ——进入安全配置界面 二,详解安全配置的选 ...
- eclipse把局部变量提为全局变量的快捷键是什么
没有缺省定义的直接快捷键,或者就按Ctrl+1按照melord说的那样做,或者自己在Preference/General/Keys自己对Convert Local Variable to Feild进 ...
- Mac 系统变量
vim .bash_profile ========================= MAVEN_HOME = < ... > export MAVEN_HOME =========== ...
- express --- session详解
之前一直做前端相关的工作,所以不太清楚session,也没有主动了解,最近在学node,对session的认识又有所加深,故总结之. 注: 关于session的一些配置问题,可以看这里. 第一部分: ...
- pat1087. All Roads Lead to Rome (30)
1087. All Roads Lead to Rome (30) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yu ...
- 用 JS 做一个数独游戏(二)
用 JS 做一个数独游戏(二) 在 上一篇博客 中,我们通过 Node 运行了我们的 JavaScript 代码,在控制台中打印出来生成好的数独终盘.为了让我们的数独游戏能有良好的体验,这篇博客将会为 ...
- C++ stl vector介绍
转自: STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if ...
- EF删除数据
1.方法一,面向对象 using (MyDbContent content = new MyDbContent()) { content.Entry<UserInfo>(model).St ...
- Python常用模块(一)
一.time模块 time模块提供各种操作时间的函数 时间三种格式 1.时间戳 以1970年1月1日 00:00:00开始的秒数 2.本地时间 localtime,表示计算机当前的时间 3.UTC世界 ...