精华内容
参与话题
问答
  • Linux的mmap内存映射机制解析

    万次阅读 2016-04-07 19:48:38
    在讲述文件映射的概念时, ...使用简单的内存访问指令读写文件;另一方面, 它也可以用于内核的基本组织模式, 在这种模式种, 内核将整个地址空间视为诸如文件之类的一组不同对象的映射. 中的传统文件访问方式是, 首先用

           在讲述文件映射的概念时,不可避免的要牵涉到虚存(SVR 4VM).实际上,文件映射是虚存的中心概念, 文件映射一方面给用户提供了一组措施,好似用户将文件映射到自己地址空间的某个部分,使用简单的内存访问指令读写文件;另一方面,它也可以用于内核的基本组织模式,在这种模式种,内核将整个地址空间视为诸如文件之类的一组不同对象的映射.中的传统文件访问方式是,首先用open系统调用打开文件,然后使用read, write以及lseek等调用进行顺序或者随即的I/O.这种方式是非常低效的,每一次I/O操作都需要一次系统调用.另外,如果若干个进程访问同一个文件,每个进程都要在自己的地址空间维护一个副本,浪费了内存空间.而如果能够通过一定的机制将页面映射到进程的地址空间中,也就是说首先通过简单的产生某些内存管理数据结构完成映射的创建.当进程访问页面时产生一个缺页中断,内核将页面读入内存并且更新页表指向该页面.而且这种方式非常方便于同一副本的共享.

         VM是面向对象的方法设计的,这里的对象是指内存对象:内存对象是一个软件抽象的概念,它描述内存区与后备存储之间的映射.系统可以使用多种类型的后备存储,比如交换空间,本地或者远程文件以及帧缓存等等. VM系统对它们统一处理,采用同一操作集操作,比如读取页面或者回写页面等.每种不同的后备存储都可以用不同的方法实现这些操作.这样,系统定义了一套统一的接口,每种后备存储给出自己的实现方法.这样,进程的地址空间就被视为一组映射到不同数据对象上的的映射组成.所有的有效地址就是那些映射到数据对象上的地址.这些对象为映射它的页面提供了持久性的后备存储.映射使得用户可以直接寻址这些对象.

        值得提出的是, VM体系结构独立于Unix系统,所有的Unix系统语义,如正文,数据及堆栈区都可以建构在基本VM系统之上.同时, VM体系结构也是独立于存储管理的,存储管理是由操作系统实施的,:究竟采取什么样的对换和请求调页算法,究竟是采取分段还是分页机制进行存储管理,究竟是如何将虚拟地址转换成为物理地址等等(Linux中是一种叫Three Level Page Table的机制),这些都与内存对象的概念无关.


    一、LinuxVM的实现.

          一个进程应该包括一个mm_struct(memory manage struct), 该结构是进程虚拟地址空间的抽象描述,里面包括了进程虚拟空间的一些管理信息: start_code, end_code, start_data, end_data, start_brk, end_brk等等信息.另外,也有一个指向进程虚存区表(vm_area_struct: virtual memory area)的指针,该链是按照虚拟地址的增长顺序排列的.Linux进程的地址空间被分作许多区(vma),每个区(vma)都对应虚拟地址空间上一段连续的区域, vma是可以被共享和保护的独立实体,这里的vma就是前面提到的内存对象

      下面是vm_area_struct的结构,其中,前半部分是公共的,与类型无关的一些数据成员,:指向mm_struct的指针,地址范围等等,后半部分则是与类型相关的成员,其中最重要的是一个指向vm_operation_struct向量表的指针vm_ops, vm_pos向量表是一组虚函数,定义了与vma类型无关的接口.每一个特定的子类,即每种vma类型都必须在向量表中实现这些操作.这里包括了: open, close, unmap, protect, sync, nopage, wppage, swapout这些操作

    struct vm_area_struct { 
    	/*公共的, 与vma类型无关的 */ 
    	struct mm_struct * vm_mm; 
    	unsigned long vm_start; 
    	unsigned long vm_end; 
    	struct vm_area_struct *vm_next; 
    	pgprot_t vm_page_prot; 
    	unsigned long vm_flags; 
    	short vm_avl_height; 
    	struct vm_area_struct * vm_avl_left; 
    	struct vm_area_struct * vm_avl_right; 
    	struct vm_area_struct *vm_next_share; 
    	struct vm_area_struct **vm_pprev_share; 
    	/* 与类型相关的 */ 
    	struct vm_operations_struct * vm_ops; 
    	unsigned long vm_pgoff; 
    	struct file * vm_file; 
    	unsigned long vm_raend; 
    	void * vm_private_data;
    }; 

    vm_ops: open, close, no_page, swapin, swapout……


    二、驱动中的mmap()函数解析

           设备驱动的mmap实现主要是将一个物理设备的可操作区域(设备空间)映射到一个进程的虚拟地址空间。这样就可以直接采用指针的方式像访问内存的方式访问设备。在驱动中的mmap实现主要是完成一件事,就是实际物理设备的操作区域到进程虚拟空间地址的映射过程。同时也需要保证这段映射的虚拟存储器区域不会被进程当做一般的空间使用,因此需要添加一系列的保护方式。

    /*主要是建立虚拟地址到物理地址的页表关系,其他的过程又内核自己完成*/
    static int mem_mmap(struct file* filp,struct vm_area_struct *vma)
    {
        /*间接的控制设备*/
        struct mem_dev *dev = filp->private_data;
        
        /*标记这段虚拟内存映射为IO区域,并阻止系统将该区域包含在进程的存放转存中*/
        vma->vm_flags |= VM_IO;
        /*标记这段区域不能被换出*/
        vma->vm_flags |= VM_RESERVED;
    
        /**/
        if(remap_pfn_range(vma,/*虚拟内存区域*/
            vma->vm_start, /*虚拟地址的起始地址*/
            virt_to_phys(dev->data)>>PAGE_SHIFT, /*物理存储区的物理页号*/
         dev->size,    /*映射区域大小*/        
            vma->vm_page_prot /*虚拟区域保护属性*/    
            ))
            return -EAGAIN;
    
        return 0;
    }

    具体的实现分析如下:

    vma->vm_flags |= VM_IO;
    vma->vm_flags |= VM_RESERVED;

    上面的两个保护机制就说明了被映射的这段区域具有映射IO的相似性,同时保证这段区域不能随便的换出。就是建立一个物理页与虚拟页之间的关联性。具体原理是虚拟页和物理页之间是以页表的方式关联起来,虚拟内存通常大于物理内存,在使用过程中虚拟页通过页表关联一切对应的物理页,当物理页不够时,会选择性的牺牲一些页,也就是将物理页与虚拟页之间切断,重现关联其他的虚拟页,保证物理内存够用。在设备驱动中应该具体的虚拟页和物理页之间的关系应该是长期的,应该保护起来,不能随便被别的虚拟页所替换。具体也可参看关于虚拟存储器的文章。

    接下来就是建立物理页与虚拟页之间的关系,即采用函数remap_pfn_range(),具体的参数如下:

    int remap_pfn_range(structvm_area_struct *vma, unsigned long addr,unsigned long pfn, unsigned long size, pgprot_t prot)

    1、struct vm_area_struct是一个虚拟内存区域结构体,表示虚拟存储器中的一个内存区域。其中的元素vm_start是指虚拟存储器中的起始地址。
    2、addr也就是虚拟存储器中的起始地址,通常可以选择addr = vma->vm_start。
    3、pfn是指物理存储器的具体页号,通常通过物理地址得到对应的物理页号,具体采用virt_to_phys(dev->data)>>PAGE_SHIFT.首先将虚拟内存转换到物理内存,然后得到页号。>>PAGE_SHIFT通常为12,这是因为每一页的大小刚好是4K,这样右移12相当于除以4096,得到页号。
    4、size区域大小
    5、区域保护机制。
    返回值,如果成功返回0,否则正数。


    三、系统调用mmap函数解析

            介绍完VM的基本概念后,我们可以讲述mmapmunmap系统调用了.mmap调用实际上就是一个内存对象vma的创建过程,

    1、mmap函数

           Linux提供了内存映射函数mmap,它把文件内容映射到一段内存上(准确说是虚拟内存上),通过对这段内存的读取和修改,实现对文件的读取和修改 。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作

    先来看一下mmap的函数声明:

    头文件: 
    <unistd.h> 
    <sys/mman.h> 
    
    原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offsize); 
    
    /*
    返回值: 成功则返回映射区起始地址, 失败则返回MAP_FAILED(-1). 
    
    参数: 
    	addr: 指定映射的起始地址, 通常设为NULL, 由系统指定. 
    	length: 将文件的多大长度映射到内存. 
    	prot: 映射区的保护方式, 可以是: 
    		PROT_EXEC: 映射区可被执行. 
    		PROT_READ: 映射区可被读取. 
    		PROT_WRITE: 映射区可被写入. 
    		PROT_NONE: 映射区不能存取. 
    	flags: 映射区的特性, 可以是: 
    		MAP_SHARED: 对映射区域的写入数据会复制回文件, 且允许其他映射该文件的进程共享. 
    		MAP_PRIVATE: 对映射区域的写入操作会产生一个映射的复制(copy-on-write), 对此区域所做的修改不会写回原文件. 
    		此外还有其他几个flags不很常用, 具体查看linux C函数说明. 
    	fd: 由open返回的文件描述符, 代表要映射的文件. 
    	offset: 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射.
    */

    mmap的作用是映射文件描述符fd指定文件的 [off,off + len]区域至调用进程的[addr, addr + len]的内存区域, 如下图所示:


    mmap系统调用的实现过程是

    1.先通过文件系统定位要映射的文件;

    2.权限检查,映射的权限不会超过文件打开的方式,也就是说如果文件是以只读方式打开,那么则不允许建立一个可写映射; 

    3.创建一个vma对象,并对之进行初始化; 

    4.调用映射文件的mmap函数,其主要工作是给vm_ops向量表赋值;

    5.把该vma链入该进程的vma链表中,如果可以和前后的vma合并则合并;

    6.如果是要求VM_LOCKED(映射区不被换出)方式映射,则发出缺页请求,把映射页面读入内存中.


    2、munmap函数

          munmap(void * start, size_t length):

          该调用可以看作是mmap的一个逆过程.它将进程中从start开始length长度的一段区域的映射关闭,如果该区域不是恰好对应一个vma,则有可能会分割几个或几个vma.

          msync(void * start, size_t length, int flags):

         把映射区域的修改回写到后备存储中.因为munmap时并不保证页面回写,如果不调用msync,那么有可能在munmap后丢失对映射区的修改.其中flags可以是MS_SYNC, MS_ASYNC, MS_INVALIDATE, MS_SYNC要求回写完成后才返回, MS_ASYNC发出回写请求后立即返回, MS_INVALIDATE使用回写的内容更新该文件的其它映射.该系统调用是通过调用映射文件的sync函数来完成工作的.

         brk(void * end_data_segement):

    将进程的数据段扩展到end_data_segement指定的地址,该系统调用和mmap的实现方式十分相似,同样是产生一个vma,然后指定其属性.不过在此之前需要做一些合法性检查,比如该地址是否大于mm->end_code, end_data_segementmm->brk之间是否还存在其它vma等等.通过brk产生的vma映射的文件为空,这和匿名映射产生的vma相似,关于匿名映射不做进一步介绍.库函数malloc就是通过brk实现的.


    四、实例解析

           下面这个例子显示了把文件映射到内存的方法,源代码是:

    /************关于本文 档********************************************
    *filename: mmap.c
    *purpose: 说明调用mmap把文件映射到内存的方法
    *wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
    Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
    *date time:2008-01-27 18:59 上海大雪天,据说是多年不遇
    *Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
    * 但请遵循GPL
    *Thanks to:
    *                Ubuntu 本程序在Ubuntu 7.10系统上测试完全正常
    *                Google.com 我通常通过google搜索发现许多有用的资料
    *Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
    * 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
    *********************************************************************/
    #include <sys/mman.h> /* for mmap and munmap */
    #include <sys/types.h> /* for open */
    #include <sys/stat.h> /* for open */
    #include <fcntl.h>     /* for open */
    #include <unistd.h>    /* for lseek and write */
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
    	int fd;
    	char *mapped_mem, * p;
    	int flength = 1024;
    	void * start_addr = 0;
    
    	fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    	flength = lseek(fd, 1, SEEK_END);
    	write(fd, "\0", 1); /* 在文件最后添加一个空字符,以便下面printf正常工作 */
    	lseek(fd, 0, SEEK_SET);
    	mapped_mem = mmap(start_addr, flength, PROT_READ,        //允许读
    		MAP_PRIVATE,       //不允许其它进程访问此内存区域
    			fd, 0);
    	
    	/* 使用映射区域. */
    	printf("%s\n", mapped_mem); /* 为了保证这里工作正常,参数传递的文件名最好是一个文本文件 */
    	close(fd);
    	munmap(mapped_mem, flength);
    	return 0;
    }

    编译运行此程序:

    gcc -Wall mmap.c
    ./a.out text_filename

    上面的方法因为用了PROT_READ,所以只能读取文件里的内容,不能修改,如果换成PROT_WRITE就可以修改文件的内容了。又由于 用了MAAP_PRIVATE所以只能此进程使用此内存区域,如果换成MAP_SHARED,则可以被其它进程访问,比如下面的

    #include <sys/mman.h> /* for mmap and munmap */
    #include <sys/types.h> /* for open */
    #include <sys/stat.h> /* for open */
    #include <fcntl.h>     /* for open */
    #include <unistd.h>    /* for lseek and write */
    #include <stdio.h>
    #include <string.h> /* for memcpy */
    
    int main(int argc, char **argv)
    {
    	int fd;
    	char *mapped_mem, * p;
    	int flength = 1024;
    	void * start_addr = 0;
    
    	fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    	flength = lseek(fd, 1, SEEK_END);
    	write(fd, "\0", 1); /* 在文件最后添加一个空字符,以便下面printf正常工作 */
    	lseek(fd, 0, SEEK_SET);
    	start_addr = 0x80000;
    	mapped_mem = mmap(start_addr, flength, PROT_READ|PROT_WRITE,        //允许写入
    		MAP_SHARED,       //允许其它进程访问此内存区域
    		fd, 0);
    
    	* 使用映射区域. */
    	printf("%s\n", mapped_mem); /* 为了保证这里工作正常,参数传递的文件名最好是一个文本文 */
    	while((p = strstr(mapped_mem, "Hello"))) { /* 此处来修改文件 内容 */
    		memcpy(p, "Linux", 5);
    		p += 5;
    	}
    	
    	close(fd);
    	munmap(mapped_mem, flength);
    	return 0;
    }


    五、mmap和共享内存对比

          共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制。共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制实现,也可以通过系统V共享内存机制实现。应用接口和原理很简单,内部机制复杂。为了实现更安全通信,往往还与信号灯等同步机制共同使用。

    对比如下:

          mmap机制:就是在磁盘上建立一个文件,每个进程存储器里面,单独开辟一个空间来进行映射。如果多进程的话,那么不会对实际的物理存储器(主存)消耗太大。

          shm机制:每个进程的共享内存都直接映射到实际物理存储器里面。

    1、mmap保存到实际硬盘,实际存储并没有反映到主存上。优点:储存量可以很大(多于主存);缺点:进程间读取和写入速度要比主存的要慢。

    2、shm保存到物理存储器(主存),实际的储存量直接反映到主存上。优点,进程间访问速度(读写)比磁盘要快;缺点,储存量不能非常大(多于主存)

    使用上看:如果分配的存储量不大,那么使用shm;如果存储量大,那么使用mmap


    展开全文
  • 内存映射文件原理

    2020-05-11 17:55:44
      虚拟内存和内存映射文件都是将一部分文件加载到内存,另一部分文件保存在磁盘上的一种机制。但是二者是有区别的: 架构不同,虚拟内存是构建在物理内存之上的,引入原因是实际物理内存无法满足程序所需的内存...

    内存映射文件与虚拟内存的区别

      内存映射文件是由操作系统支持的一种文件处理方式,通过文件映射,让用户处理磁盘文件时就如同操作内存一样。再处理大文件时,效率比传统IO高很多。
      虚拟内存和内存映射文件都是将一部分文件加载到内存,另一部分文件保存在磁盘上的一种机制。但是二者是有区别的:

    1. 架构不同,虚拟内存是构建在物理内存之上的,引入原因是实际物理内存无法满足程序所需的内存空间;内存映射文件架构在进程地址空间之上,引入原因是无法将整个大文件全部加载到内存空间
    2. 虚拟内存管理的是页面文件,内存映射文件可以是任意磁盘文件。

    映射原理

      映射其实就是在虚拟地址空间和磁盘地址空间建立了一个一一对应关系,在逻辑地址空间为文件复配一个大小相等的逻辑空间。在文件映射过程中并没有数据拷贝,文件并没有放入内存,只是逻辑上放入了内存中,具体到代码就是建立了初始化数据结构,这个过程由mmap()系统调用实现的,所以映射效率非常高。
      映射过程如下:

    1. 调用mmap()函数,相当于给磁盘文件分配虚拟内存空间,它返回一个指针ptr,这个指针指向的是一个逻辑地址,操作系统要操作其中的数据必须通过MMU翻译才能获取对应的内存物理地址。
    2. 建立内存映射并没有数据拷贝,这时通过MMU翻译ptr是无法找到与之对应的内存物理地址的,也就是MMU失败,产生一个缺页中断,缺页中断响应函数会在磁盘的交换区查找相应页面,如果找不到证明文件还未读入磁盘,则通过mmp()建立的映射关系将文件加载到物理内存中,如果在交换区找到对应文件则换入
    3. 如果在数据拷贝过程中发现内存不够用,则通过虚拟内存管理将部分页面数据换出到交换区。

    mmap() 函数

    mmap基础概念

      mmap是一种内存映射文件的方法,是将文件或者其他对象映射到进程的地址空间中去,实现磁盘地址和虚拟空间地址一一对映关系,实现这样的映射关系后,进程就可以采用指针的方式操作这段内存,而系统会将修改后的脏页面自动写回磁盘中去。使用内存映射文件时,不用调用read,write等系统调用函数。内核空间对映射区域内容进行修改也能反映到用户空间,从而实现文件共享。
    在这里插入图片描述
      进程的虚拟地址空间由多个虚拟内存区域组成,虚拟内存区域是进程虚拟地址空间的一个同质区域,及具有同样特性的连续地址范围,上图中的text数据段、初始化数据段、bss数据段等都是一个独立的虚拟地址区域,内存映射文件地址空间处于堆、栈地址空间之间的空余部分。inux内核使用vm_area<struct结构来表示一个独立的虚拟内存区域,每个不同质的虚拟内存区域功能和内部机制都不一样,因此一个进程有多个vm_area_struct数据结构组成,每个数据结构使用链表相连,如下图(以上两图来自于此博文

    在这里插入图片描述
      vm_area_struct结构包含了区域起始地址和其他信息,mmap()函数就是创建了一个vm_area_struct结构,并将其与磁盘地址相连。

    mmap映射原理

      mmap映射分为三个阶段:

    (一)启动映射过程,创建一个虚拟映射区域,封装成vm_area_struct结构

    1. 进程调用用户空间库函数void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset),在当前进程的虚拟空间找以一段连续的大小满足被映射文件大小要求的虚拟地址区域

    2. 为此虚拟地址区域分配一个vm_area_struct结构,并初始化该结构

    3. 将该结构插入进程的虚拟地址区域链中
      (二)调用内核空间的系统调用函数mmap(不同于用户空间的mmap库函数),实现物理地址与虚拟地址一一映射关系

    4. 通过内核函数int mmap(struct file *filp, struct vm_area_struct *vma)建立虚拟地址与磁盘地址的一一映射关系

    (三)进程发起对映射空间的访问,产生缺页中断,中断函数实现从磁盘拷贝到物理内存上

    1. 进程操作文件发现数据页没在内存中则到交换区中查找,如果找不到证明数据还未加载,因此内核直接将磁盘数据复制到用户空间中,实现高效拷贝

    mmap优点

    1. 对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率
    2. 实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉
    3. 提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的
    4. 可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。换句话说,但凡是需要用磁盘空间代替内存的时候,mmap都可以发挥其功效

    mmap相关函数

    1. void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
      成功执行时,mmap()返回被映射区的指针。失败时,mmap()返回MAP_FAILED[其值为(void *)-1]
      参数介绍:
      start:映射区的开始地址
      length:映射区的长度
      prot: 期望的内存保护标志
      fd:有效的文件描述词
      offset:被映射对象内容的起点

    2. int munmap( void * addr, size_t len )
      成功执行时,munmap()返回0。失败时,munmap返回-1。该调用在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小;

    参考:
    参考1
    参考2

    展开全文
  • 内存映射的原理

    千次阅读 2018-05-09 16:26:54
    这不是问题,因为大多数程序只占用实际可用内存的一小部分。在将磁盘上的数据映射到进程的虚拟地址空间的时,内核必须提供数据结构,以建立虚拟地址空间的区域和相关数据所在位置之间的关联。例如,在映射文本文件时...

    原文:http://www.cnblogs.com/wuchanming/p/4823444.html

    由于所有用户进程总的虚拟地址空间比可用的物理内存大很多,因此只有最常用的部分才与物理页帧关联。这不是问题,因为大多数程序只占用实际可用内存的一小部分。

    在将磁盘上的数据映射到进程的虚拟地址空间的时,内核必须提供数据结构,以建立虚拟地址空间的区域和相关数据所在位置之间的关联。例如,在映射文本文件时,映射的虚拟内存区必须关联到文件系统的硬盘上存储文件内容的区域。如图所示:

    当然,给出的是简化的图,因为文件数据在硬盘上的存储通常并不是连续的,而是分布到若干小的区域。内核利用address_space数据结构,提供一组方法从后备存储器读取数据。例如,从文件系统读取。因此address_space形成了一个辅助层,将映射的数据表示为连续的线性区域,提供给内存管理子系统。

    按需分配和填充页称为按需调页法。它基于处理器和内核之间的交互,使用的各种数据结构如图所示:

    过程如下:

    CPU将一个虚拟内存空间中的地址转换为物理地址,需要进行两步(如下图):

    首先,将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!),CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线程地址,

    其次,再利用其页式内存管理单元,转换为最终物理地址。

         

     这样做两次转换,的确是非常麻烦而且没有必要的,因为直接可以把线性地址抽像给进程。之所以这样冗余,Intel完全是为了兼容而已。

    • 进程试图访问用户地址空间中的一个内存地址,利用上面的线性地址去查找页表,确定对应的物理地址,但使用的页表无法确定物理地址(物理内存中没有关联页)
    • 处理器接下来触发一个缺页异常,发送到内核。
    • 内核会检查负责缺页区域的进程地址空间数据结构,找到适当的后备存储器,或者确认该访问实际上是不正确的(未映射,未使用)
    • 分配物理内存页,并从后备存储器读取所需数据填充。
    • 借助于页表将物理内存页并入到用户进程的地址空间,应用程序恢复执行。

    这些操作对用户进程是透明的。换句话说,进程不会注意到页是实际在物理内存中,还是需要通过按需调页加载。

     

    在整个过程中可能需要解决以下几个问题:

    1)系统如何感知进程当前所需页面不在主存(页表机制);
    2)当发现缺页时,如何把所缺页面调入主存(缺页中断机构);
    3)在置换页面时,根据什么策略选择欲淘汰的页面(置换算法)。

    页表机制

     

    状态位(中断位):标识该页是否在内存(0或1);
    访问位:标识该页面的近来的访问次数或时间(换出);
    修改位:标识此页是否在内存中被修改过;
    外存地址:记录该页面在外存上的地址,即(外存而非内存的)物理块号。

    缺页中断机制

    程序在执行时,首先检查页表,当状态位指示该页不在主存时,则引起一个缺页中断发生,其中断执行过程与一般中断相同:
    保护现场(CPU环境);
    中断处理(中断处理程序装入页面);
    恢复现场,返回断点继续执行。

    置换算法

    FIFO

    LRU

    LFU


    展开全文
  • 内存映射机制(mmap)

    千次阅读 2018-11-15 01:03:48
    MMU位于CPU与物理内存之间,它包含从虚地址向物理内存地址转化的映射信息。当CPU引用一个内存位置时,MMU决定哪些页需要驻留(通常通过移位或屏蔽地址的某些位)以及转化虚拟页号到物理页号。 当某个进程读取磁盘...
    • 当CPU读取数据时,是由内存管理单元(MMU)管理的。MMU位于CPU与物理内存之间,它包含从虚地址向物理内存地址转化的映射信息。当CPU引用一个内存位置时,MMU决定哪些页需要驻留(通常通过移位或屏蔽地址的某些位)以及转化虚拟页号到物理页号。
      在这里插入图片描述
    • 当某个进程读取磁盘上的数据时,进程要求其缓冲通过read()系统调用填满,这个系统调用导致内核想磁盘控制硬件发出一条命令要从磁盘获取数据。磁盘控制器通过DMA直接将数据写入内核的内存缓冲区,不需要CPU协助。当请求read()操作时,一旦磁盘控制器完成了缓存的填写,内核从内核空间的临时缓存拷贝数据到进程指定的缓存中。
    • 用户空间是常规进程所在的区域,该区域执行的代码不能直接访问硬件设备。内核空间是操作系统所在的区域,该区域可以与设备控制器通讯,控制用户区域进程的运行状态。
      在这里插入图片描述
    • 内存映射文件技术是操作系统提供的一种新的文件数据存取机制,利用内存映射文件技术,系统可以在内存空间中为文件保留一部分空间,并将文件映射到这块保留空间,一旦文件被映射后,操作系统将管理页映射缓冲以及高速缓冲等任务,而不需要调用分配、释放内存块和文件输入/输出的API函数,也不需要自己提供任何缓冲算法。
    • 使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O 操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。

    linux 内存映射机制

    void  *mmap(void  *start,  size_t length,  int prot,  int flags,  int fd,  off_t offsize)
    int  munmap(void *start,   size_t length)
    

    mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。 munmap执行相反的操作,删除特定地址区域的对象映射。
    在这里插入图片描述

    • 返回说明:

    成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED(其为(void*)-1),munmap 返回-1。

    • 参数:

    start:映射区的开始地址。
    length:映射区的长度。
    prot:映射区域的保护方式。可以为以下几种方式的组合

    
        PROT_EXEC //页内容可以被执行
        PROT_READ //页内容可以被读取
        PROT_WRITE //页可以被写入
        PROT_NONE //页不可访问
    
    

    flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体

    MAP_FIXED //使用指定的映射起始地址,如果由 start和len 参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
    MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到 msync()或者munmap() 被调用,文件实际上不会被更新。
    MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
    MAP_DENYWRITE //这个标志被忽略。
    MAP_EXECUTABLE //同上
    MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
    MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
    MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
    MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
    MAP_ANON //MAP_ANONYMOUS 的别称,不再被使用。
    MAP_FILE //兼容标志,被忽略。
    MAP_32BIT //将映射区放在进程地址空间的低 2GB,MAP_FIXED 指定时会被忽略。当前这个标志只在 x86-64平台上得到支持。
    MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
    MAP_NONBLOCK //仅和MAP_POPULATE 一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。
    
    

    fd:有效的文件描述词。
    offset:被映射对象内容的起点

    转载于:https://blog.csdn.net/aspirinvagrant/article/details/18991263

    展开全文
  • 内存映射机制

    2017-05-19 23:49:00
    MMU位于CPU与物理内存之间,它包含从虚拟地址向物理内存地址转化的映射信息。当CPU引用一个内存位置时,MMU决定哪些页需要驻留(通常通过移位或屏蔽地址的某些位)以及转化虚拟页号到物理页号。     当某个进程...
  • 操作系统内存映射机制

    千次阅读 2012-12-02 12:43:59
    这个问题思考的是程序与内存映射问题? (请高手指教) 程序在编译以后,被分配到了一个4G的逻辑地址空间当中, 在这当中是以分区段的方式进行管理的(如有代码段,数据段,堆栈段等) 。 那么,如何将...
  • Linux内存映射机制

    千次阅读 2019-04-24 21:13:27
    2.提供硬件机制内存访问权限检查 没有启动或者没有MMU时,外设(包括物理内存)等所有部件使用的都是物理地址,cpu通过物理地址来访问外设(包括物理内存)。启动MMU后,CPU核心对外发出虚拟地址给MMU,MMU把虚拟...
  • 在进入正题前先来谈谈操作系统内存管理机制的发展历程,了解这些有利于我们更好的理解目前操作系统的内存管理机制。 一 早期的内存分配机制 在 早期的计算机中,要运行一个程序,会把这些程序全都装入内存,程序...
  • 外设内存映射机制

    千次阅读 2011-09-15 23:59:03
    外设内存映射机制    一个开发板的CPU地址引脚并不是所有的都与内存元器件相连的,如果该板上有外设(如一块独立显卡),那么CPU就需要分出一些引脚来与该外设的地址引脚相连,相当于将一部分内存寻址的空间分给...
  • 共享内存主要是通过映射机制实现的。 Windows 下进程的地址空间在逻辑上是相互隔离的,但在物理上却是重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。当调用CreateFileMapping 创建命名的内存映射...
  • RocketMQ的存储文件 RocketMQ的存储文件包括CommitLog文件、ConsumerQueue文件和IndexFile文件。 CommitLog :消息存储文件,所有消息主题的消息都存储在 CommitLog 文件中。 Commitlog 文件存储目录为${ROCKET_...
  • Linux内存映射——mmap

    万次阅读 2013-03-23 17:00:10
    所谓的内存映射就是把物理内存映射到进程的地址空间之内,这些应用程序就可以直接使用输入输出的地址空间,从而提高读写的效率。Linux提供了mmap()函数,用来映射物理内存。在驱动程序中,应用程序以设备文件为对象...
  • 关于ARM的统一编制与内存映射机制

    千次阅读 2016-08-18 15:10:24
    ARM是统一编址的,也就是外设和内存进行统一的编址,共同形成了4G物理地址空间(32位为例子)。 大家知道操作外设时,实际上操作的是读写...他们被连续地编址,对于其编址的方式有两种一种是IO映射、一种是内存映射。 I
  • 内存映射 : 内存映射文件不同于文件I/O操作,内存映射实际用到了Windows的核心编程技术–内存管理。 使用内存映射文件的一般方法:  首先要通过CreateFile()函数来创建或打开一个文件内核对象,这个对象标识了磁盘...
  • 内存映射文件

    千次阅读 2013-08-11 16:48:36
    内存映射文件,是由一个文件到一块内存的映射。Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将...
  • 内存映射文件详解(Windows)

    千次阅读 2017-07-07 13:47:13
    什么是内存映射文件内存映射文件,是由一个文件到一块内存的映射。 Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址...
  • 内存映射文件原理探索

    万次阅读 多人点赞 2016-11-27 17:10:09
    虚拟内存与内存映射文件的区别与联系 二者的联系虚拟内存和内存映射文件都是将一部分内容加载到,另一部分放在磁盘上的一种机制,二者都是应用程序动态性的基础,由于二者的虚拟性,对于用户都是透明的. 虚拟内存其实...
  • 本文主要讲述大量数据的文件的内存映射机制的实现。 1. 内存映射 内存映射文件,是由一个文件到一块内存的映射。Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping)。内存映射文件与虚拟内存...
  • 虚拟内存机制 转载处:http://blog.csdn.net/zp373860147/article/details/7815793; 这是我找到的关于虚拟内存和分页机制的我个人比较容易理解的一篇文章。  虚拟存储器的思想是程序、数据和堆栈的大小都...
  • 根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制。 本文目的: 对Windows内存管理机制了解清楚,有效的利用C++内存函数管理和使用内存。 本文内容: ...
  • 内存映射

    千次阅读 2014-06-17 11:02:00
    这就意味着内核把对线性区中页内某个字节的访问转换成对文件中相应字节的操作,这种技术称为内存映射。 有两种类型的内存映射: 共享型: 在线性区页上的任何写操作都会修改磁盘上的文件;而且,如果进程对共享映射...
  • Java NIO内存映射---上G大文件处理

    万次阅读 多人点赞 2015-09-16 08:43:31
    本文主要讲了java中内存映射的原理及过程,与传统IO进行了对比,最后,用实例说明了结果。
  • linux 内存映射 PCI内存映射 DMA映射

    千次阅读 2012-04-13 13:50:38
    内存映射, 就是指把外设的内存映射到用户空间访问。系统调用为:  #include  void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);  其中fd 可以为打开的普通文件或设备...
  • 内存映射与端口映射

    千次阅读 2015-12-14 08:42:30
    一、概念理解 ...CPU对外设IO端口物理地址的编址方式有两种:一种是I/O映射方式(I/O-mapped,也称“端口映射”),另一种是内存映射方式(Memory-mapped)。而具体采用哪一种则取决于CPU的体系结构
  • mongodb内存映射原理

    千次阅读 2019-07-05 15:15:01
    内存映射 mongodb非常吃内存,为啥这么吃内存呢,mongodb使用的是内存映射存储引擎,即Memory Mapped Storage Engine,简称MMAP,MMAP可以把磁盘文件的一部分或全部内容直接映射到内存,这样文件中的信息位置就会在...
  • VC中用内存映射文件处理大文件

    千次阅读 2015-04-26 23:40:52
    文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。一般来说,以上这些函数可以满足大多数...
  • Linux进程间通信—— 内存映射

    千次阅读 2017-07-29 10:26:08
    两个不同进程A、B共享内存的意思是,同一块物理内存映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁...
  • 内存映射文件(专门读写大文件)

    万次阅读 2017-01-19 21:28:26
    引言  文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。一般来说,以上这些函数可以满足...
  • Windows内存管理 - 内存映射文件

    千次阅读 2012-03-17 12:57:38
    内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据。 • 内存堆栈,最适合用来管理大量的小对象。  内存映射文件可以用于3个不同的目的 • 系统使用内存...

空空如也

1 2 3 4 5 ... 20
收藏数 520,698
精华内容 208,279
关键字:

内存映射机制