精华内容
下载资源
问答
  • 内存映射

    2014-08-24 14:38:06
  • 文章目录Linux 内存映射之文件映射文件映射 匿名映射文件的私有映射与共享映射创建映射 mmap()文件映射的边界情况正常文件范围的内存映射超出文件范围的内存映射同步映射区域到文件 msync()解除映射区域 munmap()...

    Linux 内存映射之文件映射

    文件映射 匿名映射

    在Linux的内存映射中,主要分为文件映射和匿名映射,其中映射又具有私有映射和共享映射两种方式,本文中,仅讨论文件的私有映射和文件的共享映射。

    文件映射: 文件映射是将文件的一部分直接映射到该进程的虚拟内存中,文件被映射后,可以通过访问虚拟内存来访问文件内容;

    文件的私有映射与共享映射

    文件的私有映射: 文件被映射到虚拟内存中后,虚拟内存中的内容是可读可写的,但是对私有映射来说,文件映射到的虚拟内存上的内容更改是不会被写入真正的文件中,既对虚拟内存内容的更改仅仅只对该进程本身可见,所以说映射内容是该进程私有的。文件的私有映射主要用途是使用文件的内容来初始化一块内存区域。

    文件的共享映射: 与私有映射相反,共享映射中,文件映射到的虚拟内存上的内容更改是会被写入到真正的文件中的。只是虚拟内存中的内容更改被同步到文件中的时机并不是立即的,内核不保证这种同步操作何时发生,但是可以通过msync()函数来显示的执行同步操作。共享映射提供了另一种文件IO操作的方法,并且共享映射允许不相关的进程共享一块文件内容。
    文件映射相对read()和write()的优劣:

    1. 在大型文件的重复随机访问中,文件映射的优势突出,方便应用,代码简捷;
    2. read()和write()操作需要两次传输:一次是在文件和内核高速缓存之间,另一次是内核高速缓存和用户空间缓存之间。使用文件映射就无需第二次传输了。
    3. 如果是顺序的访问文件,执行read() write()时使用的缓冲区大小足够大,以至于能够避免执行大量的I/O系统调用,那么mmap()带来的系统提升是非常有限,或者没有提升。
    4. 对于小数据量的I/O操作,mmap()的开销比read() write()大;

    创建映射 mmap()

    #include <sys/mman.h>
    /*
     *  @Description: 创建一个映射(文件映射、匿名映射均可)
     *  @Para       : void *addr      指定映射被放置的虚拟地址
     *                size_t length   映射的字节数
     *                int port        位掩码,映射后虚拟地址的保护信息
     *                int flags       私有映射 MAP_PRIVATE  或  共享映射 MAP_SHARED 等
     *                int fd          要映射的文件标识符
     *                int offset      文件偏移,指定文件映射的起点,必须是系统分页大小的整数倍
     * 
     *  @return     : 成功返回映射后虚拟地址的首地址,失败返回MAP_FAILED
    **/
    void * mmap(void *addr, size_t length, int port, int flags, int fd, off_t offset);
    

    注意:

    1. 函数的void * addr参数指定了映射被放置的虚拟内存,如何改参数指定为NULL,则内核会为该映射自动分配合适的地址。这是创建映射的首选做法;
    2. 如果void * addr被设置为非NULL值,那么默认将该参数值作为提示信息来处理,实际中,内核会将该值舍入到最近的一个分页边界处,进行边界对齐;
    3. size_t length 参数指定了映射字节数,因为内核创建映射的最小单位为分页大小,因此实际上创建虚拟内存的长度会被向上提升为分页大小的下一个倍数;
    4. int port 是位掩码,用来指定映射后的虚拟内存保护信息,其掩码取值如下:
      PROT_NONE 区域无法访问,该项不能与其它项相或
      PROT_READ 区域内容可读取
      PROT_WRITE 区域内容可修改
      PROT_EXEC 区域内容可执行
    5. int flags 是控制映射操作各方面的位掩码,该掩码必须包含MAP_PRIVATE和MAP_SHARED其中之一,除了这两种外,还可以或上其它的标记。
      MAP_ANONYMOUS 创建一个匿名映射
      MAP_FIXED 原样的解释addr参数 (addr参数不被按照分页大小进行舍入)
      MAP_LOCKED 将映射分页锁进内存
      MAP_HUGETLB 创建一个使用巨页的映射
      MAP_NORESERVE 控制交换空间的预留
      MAP_PRIVATE 对映射数据的修改是私有的
      MAP_POPULATE 填充一个映射的分页
      MAP_SHARED 与MAP_PRIVATE相反
      MAP_UNINITIALIZED 创建匿名映射时不初始化虚拟内存为零
    6. int offset 指定了文件要映射的起点,且必须是系统分页大小的整数倍;
    7. 系统分页大小为 sysconf(_SC_PAGESIZE) 的返回值,Linux系统中该值通常为4096Byte;

    文件映射的边界情况

    正常文件范围的内存映射

    在这里插入图片描述
    如上图所示,对某个大小为9500Byte的文件执行如下映射程序:

    //从文件的位置0(即文件起始位置)开始映射,映射长度为6000。
    void * addr = mmap(NULL, 6000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    
    1. 由于映射长度6000并非系统分页大小的整数倍,所以会按照分页大小,自动向上取整,所以实际映射大小为8092Byte,即文件从起始位置有8092Byte映射到虚拟内存中。
    2. 文件中未被映射的区域是无法通过虚拟内存进行访问的,如果强制向虚拟内存末尾后面访问,则会访问到一片未定义的地址,产生SIGSEGV信号,默认该信号会终止进程,并打印core dump;
    3. 由于实际文件映射大小为8092Byte,且为共享映射,所以映射后虚拟内存的8092Byte可读可写,且修改的内容会同步到实际文件中。

    超出文件范围的内存映射

    在这里插入图片描述
    如上图所示,对某个大小为2200Byte的文件执行如下映射程序:

    //从文件的位置0(即文件起始位置)开始映射,映射长度为6000。
    void * addr = mmap(NULL, 6000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    
    1. 映射长度为6000,自动向上对齐系统分页,所以实际映射大小为8092Byte。但文件的实际大小为2200Byte。所以长度为8092Byte的虚拟内存映射区域被分为三段。
      • 第一段,即实际真实文件映射大小2200Byte,该区域是可读、可写,且修改内容会同步到真实文件中;
      • 第二段,即第一个分页中除开首部2200Byte的剩余部分,大小为1896Byte,该部分可读可写,但由于没有文件映射与该内存相对应,所以写入内容无法同步到真实文件中;
      • 第三段,即第二个分页,该分页无文件与之对应,是为了映射长度的分页对齐而自动扩展的,如果访问该部分内容会产生SIGBUS信号;
    2. 访问未被映射的区域会产生SIGSEGV信号;

    注意:
    创建一个超过文件大小的映射可能是无意义的,可以通过 ftruncate() 或 write()去扩充文件大小,然后再映射,使映射变得有意义。

    同步映射区域到文件 msync()

    在共享映射 MAP_SHARED 模式下,映射的虚拟内存中修改的内容会自动写入到真实文件中,但默认情况下,内核并不保证这种同步操作在何时发生。所以提供了一种显示的执行该操作的函数,完成映射后的虚拟内存与真实文件间的数据同步。
    调用msync()后能够保证虚拟内存中修改的内容对执行read()操作的其它进程可见。

    #include <sys/mman.h>
    
    /*
     *  @Description: 将映射后的虚拟地址修改内容同步到真实文件
     *  @Para       : void *addr      需要同步虚拟内存首地址
     *                size_t length   同步的地址内容长度
     *                int flags       同步的模式
     * 
     *  @return     : 成功返回0,失败返回-1
    **/
    int msync(void * addr, size_t length, int flags);
    

    注意:

    1. void * addr 必须是分页对齐的,size_t length 会被自动扩展到分页大小的下一个整数倍;
    2. int flags 取值如下:
      • MS_SYNC 调用会阻塞,直到虚拟内存区域中所有被修改的分页被写入到真实文件为止。调用完后,虚拟内存与磁盘内容同步。
      • MS_ASYNC 虚拟内存区域与内核高速缓存区同步,并对立即执行read()操作的其他进程可见,但会在之后的某个时刻将修改内容写入磁盘。
      • MS_INVALIDATE 使映射数据的缓存副本失效,当内存区域中所有被修改过的分页被同步到文件中之后,内存区域中所有与底层文件不一致的分页会被标记为无效。下次引用这些分页时会重新从文件的相应位置复制相应的分页内容。

    解除映射区域 munmap()

    与mmap() 操作相反,从调用进程的虚拟地址空间删除一个映射。

    #include <sys/mman.h>
    
    /*
     *  @Description: 删除一个映射
     *  @Para       : void *addr      解除映射的地址范围的起始地址
     *                size_t length   解除映射的区域长度
     * 
     *  @return     : 成功返回0,失败返回-1
    **/
    int munmap(void * addr, size_t length);
    

    注意:

    1. void * addr必须是分页对齐的, size_t length 会被自动扩展到分页大小的下一个整数倍;
    2. 可以只将整个映射区域的部分区域解除映射,也可以让length跨越多个映射,将范围内的多个映射全部解除;
    3. 为确保虚拟地址内存区域的修改内容被同步到真实文件中,需要在解除映射前调用 msync() 进行同步操作。

    文件映射程序实例

    /*
     *  @Description: 客户端从服务端接收文件
     *  @Para       : int client_fd : the socket fd of client
     *                const char * filename : name of file
     *                int filesize : size of file
     *  @return     : void
     *  @Author     : Huge
     *  @Data       : 2020.03.06 12:12
    **/
    void fileReceive(int client_fd, const char * filename, int filesize)
    {
        int filefd = open( filename, O_RDWR | O_CREAT | O_TRUNC , 666);     //打开或创建文件
        if(ftruncate( filefd, filesize) != 0)   //创建的文件大小为0,需要修改文件大小到指定文件大小
        {
            cout << "failed to ftruncate file!" << endl;
            return;
        }
    
        //将创建的文件映射到虚拟内存
        void * fileaddr = mmap(NULL, filesize, PROT_READ | PROT_WRITE , MAP_SHARED, filefd, 0);
        if(fileaddr == MAP_FAILED)
        {
            cout << "mmap " << filename << " failed!" << endl;
            return;
        }
    
        //使用服务端发送的文件内容写入到虚拟内存。
        //该处使用文件映射就是为了使用操作内存的方式来操作文件。
        //服务端使用sendfile()函数发送整个文件,接收端一个recv()即可接收整个文件。
        int revlen = recv(client_fd, fileaddr, filesize, 0);
        if(revlen == -1)
        {
            cout << "recv " << filename << " failed!" << endl;
            munmap(fileaddr, filesize);
            return;
        }
        
        if(msync(fileaddr, filesize, MS_SYNC) == -1)    //将虚拟内存同步到文件中
        {
            cout << "msync " << filename << " failed!"<< endl;
        }
        if(munmap(fileaddr, filesize) == -1)     //解除映射
        {
            cout << "munmap " << filename << " failed!"<< endl;
        }
    
        close(filefd);
    }
    

    << endl;
    }
    if(munmap(fileaddr, filesize) == -1) //解除映射
    {
    cout << “munmap " << filename << " failed!”<< endl;
    }

    close(filefd);
    

    }

    
    
    
    展开全文
  • 内存映射端口映射

    2017-09-24 17:55:30
    内存映射I/O,就是把设备的寄存器映射到常规内存空间的固定地址。例如ARM处理器。 端口映射I/O,就是把设备的寄存器映射到一个单独的地址空间,这个地址空间一般来说要比常规内存小。在这些处理器上,程序必须使用...

    内存映射I/O,就是把设备的寄存器映射到常规内存空间的固定地址。例如ARM处理器。

    端口映射I/O,就是把设备的寄存器映射到一个单独的地址空间,这个地址空间一般来说要比常规内存小。在这些处理器上,程序必须使用特殊的机器指令来向内存映射设备的寄存器读取或写入值,比如在intel x86上使用in和out指令。

    展开全文
  • 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 可以为打开的普通文件或设备...

    内存映射, 就是指把外设的内存映射到用户空间访问。系统调用为:

           #include <sys/mman.h>

           void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 

    其中fd 可以为打开的普通文件或设备文件。返回的地址为用户地址(即vma的地址, vm_area_struct, 跟描述vmalloc返回内核虚拟地址的vm_struct 不一样。)

    驱动程序中的mmap原型为:        

            int (*mmap) (struct file *filp, struct vm_area_struct *vma);

     在sysmmap系统调用到f->ops->mmap前,linux OS 已做了大量工作,包含分配vma (或合并原vma)。到此时,vma已经填好,只要将分配物理内存和建立对应的页表即可。如果有物理内存,可以通过remap_pfn_range 一次性建立全部页表,或者在vma的nopage(现新内核改成fault)中每次映射一个页面。

     

    用户进程访问用户空间地址的时候直接通过页表访问,跟vma没任何关系。vma是内核管理用户进程的用户态内存区域的。如果访问地址失败(或者缺页表,或者缺物理内存),都将将引发缺页异常。缺页异常会判定异常的原因,如果是映射的file原因,则调用vma的nopage函数,返回page指针,然后据此计算页帧号并写入对应的页表像pte。这样下次就可以访问了。

    nopage函数需要返回一个page指针(page为内核描述物理内存的结构)。如果是vmalloc分配的物理页(单个页面不划算,要分配页表),则调用vmalloc_to_page 返回页面指针;如果是get_free_pages(或者kmalloc)返回的内存,则调用virt_to_page返回page指针。(其实这两个函数实现一样,都是 mem_map [ (kaddr -3G)>>12]. 

    remap不允许映射常规内存,除非需要mem_map_reserve 先设置成保留,因常规内存由OS自己管理。

     

    PCI设备有两次映射,第一次是将外设存储映射到统一的物理地址,在系统启动的时候已经由bios做好了,分配的物理地址记录在PCI外设配置空间里面。在启动后,调用ioremap(pci_resource_start()) 返回内核虚拟地址(跟vmalloc的类似),原型为:

    void *  ioremap (unsigned long phys_addr, unsigned long size) 然后可以用专用的IO端口操作函数操作 ioread/iowrite. 

     

    DMA映射则相反,DMA映射是分配的缓冲区(内核逻辑地址,不管是dma_alloc_coherent, kmalloc等等,本质都是get_free_pages(DMA))跟一组设备可访问的物理地址的组合。dma_alloc_coherent 内部调用get_free_pages(DMA),返回该地址,同时设置对应的物理地址(总线地址返回)。  内核使用逻辑地址设置数据,然后将对应的物理地址写入DMA寄存器(即写上面的ioremap返回的地址),让DMA完成操作。

    展开全文
  • 内存映射文件mmap

    千次阅读 2020-03-27 11:25:14
    内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对...
  • MemMap内存映射

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

    2018-02-04 22:51:59
    内存映射是在调用进程的虚拟地址空间创建一个新的内存映射内存映射分为2种: 1.文件映射:将一个普通文件的全部或者一部分内容映射到进程的虚拟内存中。映射后,进程就可以直接在对应的内存区域操作文件内容! ...
  • mmap内存映射

    千次阅读 2017-04-15 10:51:15
    内存映射是个很有用,也很有意思的思想。我们都知道操作系统分为用户态和内核态,用户态是不能直接和物理设备打交道的,如果想把硬盘的一块区域读到用户态,则需要两次拷贝(硬盘->内核->用户),但是内存映射的设计只...
  • 内存映射文件原理

    2020-05-11 17:55:44
    内存映射文件内存映射文件与虚拟内存的区别映射原理mmap() 函数mmap基础概念mmap映射原理mmap优点mmap相关函数 内存映射文件与虚拟内存的区别   内存映射文件是由操作系统支持的一种文件处理方式,通过文件映射,...
  • 内存映射mmap

    2018-04-29 09:47:13
    内存映射是linux中的一个重要机制,它和虚拟内存管理和文件IO都有直接的关系,本篇将详细介绍linux中内存映射的原理。mmap基本概念 在介绍内存映射之前,首先知道现代计算机系统普遍采用虚拟内存的方式管理物理内存...
  • 内存映射 : 内存映射文件不同于文件I/O操作,内存映射实际用到了Windows的核心编程技术–内存管理。 使用内存映射文件的一般方法:  首先要通过CreateFile()函数来创建或打开一个文件内核对象,这个对象标识了磁盘...
  • mongodb内存映射原理

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

    2020-04-28 11:42:46
    内存映射 想理解这个知识点,我们首先要知道内存的概念和映射的概念。 内存的基本概念 我们先看一张计算的组成图: 内存一般分为只读存储器(ROM)和随机存储器(RAM),以及最强悍的高速缓冲存储器(CACHE),只读...
  • numpy的内存映射

    2018-08-22 11:24:36
    内存映射 Numpy 有对内存映射的支持。 内存映射也是一种处理文件的方法,主要的函数有: memmap frombuffer ndarray constructor 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域...
  • 内存映射文件

    2015-05-08 16:21:04
    内存映射文件 内存映射文件的概念:内存映射文件提供了一组独立的函数,使应用程序能够通过内存指针像访问内存一样访问磁盘上的文件。通过内存映射文件函数可以将磁盘上的文件全部或者部分映射到进程的虚拟...
  • 内存映射

    2018-08-04 10:54:03
    1、mmap - 创建内存映射区 作用:将磁盘文件的数据映射到内存,用户通过修改内存就能修改磁盘文件 函数原型: void *mmap( void *adrr, //映射区首地址,传NULL size_t length, //映射区的大小,不能为0,文件...
  • 【Python学习之路】Numpy 内存映射

    万次阅读 2019-12-15 20:52:02
    内存映射 Numpy 有对内存映射的支持。 内存映射也是一种处理文件的方法,主要的函数有: memmap frombuffer ndarray constructor 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,335
精华内容 11,334
关键字:

内存映射