zoukankan      html  css  js  c++  java
  • 内存映射文件mmap

    1.  mmap

    mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针而不需要read/write函数。
    使用内存映像文件的另一个优点是可以共享数据。如果多个进程需要访问同样的数据,这些数据就可以保存在一个内存映像文件中,所有的进程都可以访问它(进程间通信)。作为一种高效的共享内存模型,内存映像文件能够向任何进程独立地提供数据访问,并且把内存区的内容保存在一个磁盘文件中。如果选择这样的方式使用内存映像文件,还要对内存中的数据采取一种串行访问(serializing access)的方法,以保证统一的、可预测的读写操作。串行访问是指使用锁或信号灯(或者某些其他机制)来避免多个进程同时访问数据。在这种情况下,使用共享内存可能会更简单一些。


    mmap缺点:1)耗内存,碎片。2)普通文件。
        优点:1)map速度快。 2)可原子访问任一字节,不用担心offset。

    #include <sys/mman.h>
    void *mmap(void *addr, size_t len, int prot, int flag, int fd, off_t off);
    int munmap(void *addr, size_t len);
    addr:NULL,内核会自己在进程地址空间中选项合适的地址建立映射。
    len:不超过文件长度,否则总线错误。
    prot:PROT_READ,PROT_WRITE, PROT_NONE, PROT_EXEC
    flag:MAP_SHARED, MAP_PRIVATE, MAP_ANON
         MAP_SHARED映射区unmap时,修改会回写磁盘文件。
         MAP_PRIVATE不回写磁盘文件。
         MAP_ANON(匿名区)纯内存区,不依赖任何文件。
    off:文件起始偏移。

    mmap映射的内存空间位于heap和stack之间(用户空间)。

    成功返回空间地址,失败返回MAP_FAILED(=>(void *)-1)

    PROT_EXEC要求fd必须可读RDONLY,PROT_WRITE要求fd必须O_RDWR。

    map回写磁盘时直接从用户空间拷贝数据到磁盘,节省回写时间。
    常规拷贝时需要从用户空间拷贝数据到内核,然后内核回写磁盘。

    匿名映射:
    char *p = mmap(NULL, 100, PROT_WRITE|PROT_READ, MAP_SHARED, -1, 0);
    fd = -1代表与文件无关。

    应用mmap()时,mmap()调用完后可关闭fd。
    fd关闭并不影响该文件已建立的映射,仍然可以对文件进行读写。

    可用strace命令执行程序,跟踪程序执行过程中用到的所有系统调用的参数及返回值。

    举例:cat的一种不完善实现

    include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    void err_quit(char *msg)
    {
        perror(msg);
        exit(EXIT_FAILURE);
    }
    
    int main(int argc, char *argv[])
    {
        int fdin;
        char *src;
        struct stat statbuf;
        off_t len;
        if(argc != 2)
        {   
            printf("USAGE: mmcat {file}
    ");
            exit(EXIT_FAILURE);
        }
    
        if((fdin = open(argv[1], O_RDONLY)) < 0)
        {
            err_quit("open");
        }
    
        if((fstat(fdin, &statbuf)) < 0)
        {
            err_quit("fstat");
        }
    
        len = statbuf.st_size;
    
        if((src = mmap(0, len, PROT_READ, MAP_SHARED, fdin, 0)) == 
            (void *) -1)
        {
            err_quit("mmap");
        }
    
        printf("%s", src);
    
        close(fdin);
    
        munmap(src, len);
    
        return 0;
    }

    在要求高度安全性的情况下,内存映像也极具价值。因为具有超级用户权限的程序能够把内存映射锁定在内存中,不让它们因linux的内存管理机制而被交换到磁盘上,类似口令文件这样的敏感数据就不太会被扫描程序探测到。当然,在这种场合下,内存区应该被设置为PROT_NONE,这样其他进程就不能读这块内存区了。

  • 相关阅读:
    ABP文档
    SqlServer英文单词全字匹配
    npm不是以管理身份运行遇到的问题
    concurrenthashmap jdk1.8
    HashSet源码分析 jdk1.6
    Iterator设计模式--jdk1.7
    代理模式
    高并发下的HashMap,ConcurrentHashMap
    HashMap源码分析jdk1.6
    Stack&Vector源码分析 jdk1.6
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/6130059.html
Copyright © 2011-2022 走看看