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 ...
随机推荐
- dynamic:动态类型简单用法,写法
class 动态创建数据 { //动态类型:本质感觉跟object的用法差不多,只是在执行的时候才知道数据类型 public dynamic Dynamic() { //定义一个动态类型,作为返回值 ...
- springMvc使用restful风格
转载:https://blog.csdn.net/weide_java/article/details/53793769 1,REST架构师一个抽象的概念,目前主要是基于HTTP协议实现,其目的是为了 ...
- idea生成springBoot 报错403
问题: idea创建springboot失败 Initialization failed Cannot download 'https://start.spring.io': Status: 403 ...
- mysql 安装以及卸载 CentOS 7
wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar 安装:mkdir ...
- ORA-12012 ORA-20001 on ORACLE 12C (2420581.1)
Oracle数据库 - 企业版 - 12.2.0.1及更高版本本文档中的信息适用于任何平台. Doc ID 2420581.1 症状 在容器数据库中,警报日志中会显示以下错误: ORA-12012 ...
- 关于i++与++i的学习讨论!
先谈容易的知识点 区别两个 1. i++ 返回原来的值,++i 返回加1后的值. 2. i++ 不能作为左值,而++i 可以. 重点说下第二点.首先解释下什么是左值 左值是对应内存中有确定存储地址的对 ...
- Jquery load()加载GB2312页面时出现乱码的解决方法
问题描述:jquery的字符集是utf-8,load方法加载完GB2312编码静态页面后,出现中文乱码. a.php <script language="javascript" ...
- Quartz使用(1) - 初识quartz
1. 背景 由于最新的工作项目中,需要使用quartz框架,以完成相关的任务的定时执行.经过两周的调研与使用,本系列博客会参考官网及网上相关博客,结合工作项目中的使用,详细介绍quartz的各个方面. ...
- HDU5411——CRB and Puzzle——————【矩阵快速幂优化dp】
CRB and Puzzle Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)To ...
- Props 和 IActorRef 3
在Actor模式中我们使用IActorRef通过ActorSystem来发送消息数据.这么做有两个理由 1.ActorSystem会在消息中封装一些元数据(metadata),这些数据我们可以通过上下 ...