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. Install ElasticSearch plugin for head

    git clone git://github.com/mobz/elasticsearch-head.git yum install git npm cd elasticsearch-head npm ...

  2. .netcore在linux下使用P/invoke方式调用linux动态库

    http://www.mamicode.com/info-detail-2358309.html   .netcore下已经实现了通过p/invoke方式调用linux的动态链接库(*.so)文件 1 ...

  3. 网页console console.log 用法 Chrome F12

    #########sample 0 https://www.cnblogs.com/xiaozong/p/4961929.html https://blog.csdn.net/shanliangliu ...

  4. IP分片 与 TCP分段的区别 !!!!careful========以及udp中一个包大小究竟为多大合适 ==========三次握手四次挥手细节

    首先声明:TCP分片应该称为TCP分段 TCP/IP详解--TCP的分段和IP的分片 分组可以发生在运输层和网络层,运输层中的TCP会分段,网络层中的IP会分片.IP层的分片更多的是为运输层的UDP服 ...

  5. Java-IO读写文件简单操作

    Java中读写文件的关键在于节点流和处理流的的选取上,而节点流和处理流又分为面向字节.面向字符两种处理模式,因此,需要根据实际的情况选择合适的处理模式,一般而言,往往尽量尝试使用面向字符的处理模式,如 ...

  6. IOS Intro - NSDictionary and NSMutableDictionary

    NSDictionary.NSMutableDictionary的基本用法 1.不可变词典NSDictionary 字典初始化 NSNumber *numObj = [NSNumber numberW ...

  7. Fixed Function Shader

    Fixed function shader(固定管线着色器) Shader "Custom/Text01" {                        //shader名称 ...

  8. python函数(四)

    一.函数是什么? 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,编程中的函数在英文中也有很多不同的叫法.在BASIC中叫做subroutine(子过程或子程序),在Pasc ...

  9. 学习Spring.Net_1

    Spring.Net是一个轻量级的控制反转(IoC)和面向切面编程(AOP)技术的容器框架  一.控制反转(Inversion of Control,IoC),也叫依赖注入(Dependency In ...

  10. List转为DataTable并可以导出为Excel

    using com.jd120.Core.Utility; using System; using System.Collections.Generic; using System.Data; usi ...