mmap 系统调用中 MAP_ANONYMOUS 标志的目的是什么? [英] What is the purpose of MAP_ANONYMOUS flag in mmap system call?

查看:37
本文介绍了mmap 系统调用中 MAP_ANONYMOUS 标志的目的是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

man 页面,

MAP_ANONYMOUS
              The mapping is not backed by any file; its contents are initialized to zero.  The fd and offset arguments are ignored; however, some implementations  require
              fd  to  be  -1  if  MAP_ANONYMOUS  (or  MAP_ANON)  is  specified, and portable applications should ensure this.  The use of MAP_ANONYMOUS in conjunction with
              MAP_SHARED is only supported on Linux since kernel 2.4.

使用MAP_ANONYMOUS 的目的是什么?任何例子都会很好.还有从哪里映射内存?

What is the purpose of using MAP_ANONYMOUS? Any example would be good. Also From where the memory will be mapped?

man 页面上写到 MAP_ANONYMOUS 与 MAP_SHARED 的结合使用仅在 Linux 内核 2.4 之后才支持.如何与其他进程共享映射到 MAP_ANONYMOUS 的内存?

It is written on man page that The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4. How can i share the memory mapped with MAP_ANONYMOUS with other process?

推荐答案

匿名映射可以被描绘成一个归零的虚拟文件.匿名映射只是准备使用的大的、零填充的内存块.这些映射驻留在堆之外,因此不会造成数据段碎片.

Anonymous mappings can be pictured as a zeroized virtual file. Anonymous mappings are simply large, zero-filled blocks of memory ready for use. These mappings reside outside of the heap, thus do not contribute to data segment fragmentation.

MAP_ANONYMOUS + MAP_PRIVATE:

  • 每次调用都会创建一个不同的映射
  • 子级继承父级的映射
  • 孩子对继承映射的写入以写时复制的方式提供
  • 使用这种映射的主要目的是分配一个新的归零内存
  • malloc 使用匿名私有映射来处理大于 MMAP_THRESHOLD 字节的内存分配请求.
    通常,MMAP_THRESHOLD 为 128kB.

MAP_ANONYMOUS + MAP_SHARED:

  • 每次调用都会创建一个不同的映射,该映射不与任何其他映射共享页面
  • 子级继承父级的映射
  • 没有copy-on-write当其他人共享映射写入共享映射时
  • 共享匿名映射允许以类似于 System V 内存段的方式进行 IPC,但仅限于相关进程之间
  • each call creates a distinct mapping that doesn't share pages with any other mapping
  • children inherit parent's mappings
  • no copy-on-write when someone else sharing the mapping writes on the shared mapping
  • shared anonymous mappings allow IPC in a manner similar to System V memory segments, but only between related processes

在 Linux 上,有两种方法可以创建匿名映射:

On Linux, there are two ways to create anonymous mappings:

  • 指定 MAP_ANONYMOUS 标志并为 fd 传递 -1

  • specify MAP_ANONYMOUS flag and pass -1 for fd

    addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 
    if (addr == MAP_FAILED)
        exit(EXIT_FAILURE);  

  • 打开/dev/zero 并传递这个打开的 fd

  • open /dev/zero and pass this opened fd

        fd = open("/dev/zero", O_RDWR);   
        addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    

    (此方法通常用于像 BSD 这样没有 MAP_ANONYMOUS 标志的系统)

    (this method is typically used on systems like BSD, that do not have MAP_ANONYMOUS flag)

    匿名映射的优点:
    - 没有虚拟地址空间碎片;取消映射后,内存立即返还给系统
    - 它们在分配大小、权限方面是可修改的,并且它们也可以像普通映射一样接收建议
    - 每个分配都是一个不同的映射,与全局堆分开

    Advantages of anonymous mappings:
    - no virtual address space fragmentation; after unmapping, the memory is immediately returned to the system
    - they are modifiable in terms of allocation size, permissions and they can also receive advice just like normal mappings
    - each allocation is a distinct mapping, separate from global heap

    匿名映射的缺点:
    - 每个映射的大小是系统页面大小的整数倍,因此会导致地址空间的浪费
    - 创建和返回映射比从预分配的堆中产生更多的开销

    Disadvantages of anonymous mappings:
    - size of each mapping is an integer multiple of system's page size, thus it can lead to wastage of address space
    - creating and returning mappings incur more overhead than that of from the pre-allocated heap

    如果包含此类映射的程序分叉进程,则子进程将继承该映射.以下程序演示了这种继承:

    if a program containing such mapping, forks a process, the child inherits the mapping. The following program demonstrates this kinda inheritance:

    #ifdef USE_MAP_ANON
    #define _BSD_SOURCE
    #endif  
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <sys/wait.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
        /*Pointer to shared memory region*/    
        int *addr;   
    
    #ifdef USE_MAP_ANON      /*Use MAP_ANONYMOUS*/           
         addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);     
         if (addr == MAP_FAILED) {     
             fprintf(stderr, "mmap() failed
    ");     
             exit(EXIT_FAILURE);
         }      
    
    #else        /*Map /dev/zero*/     
        int fd;    
        fd = open("/dev/zero", O_RDWR);      
        if (fd == -1) {    
            fprintf(stderr, "open() failed
    ");
            exit(EXIT_FAILURE);
        }    
    
        addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);    
        if (addr == MAP_FAILED) {    
            fprintf(stderr, "mmap() failed
    ");    
            exit(EXIT_FAILURE);    
        }     
    
        if (close(fd) == -1) {          /*No longer needed*/    
            fprintf(stderr, "close() failed
    ");    
            exit(EXIT_FAILURE);    
        }
    #endif    
        *addr = 1;      /*Initialize integer in mapped region*/    
    
        switch(fork()) {        /*Parent and child share mapping*/     
        case -1:    
            fprintf(stderr, "fork() failed
    ");
            exit(EXIT_FAILURE);    
    
        case 0:         /*Child: increment shared integer and exit*/     
            printf("Child started, value = %d
    ", *addr);    
            (*addr)++;    
    
            if (munmap(addr, sizeof(int)) == -1) {    
                fprintf(stderr, "munmap()() failed
    ");    
                exit(EXIT_FAILURE);    
            }     
            exit(EXIT_SUCCESS);     
    
        default:        /*Parent: wait for child to terminate*/      
            if (wait(NULL) == -1) {    
                fprintf(stderr, "wait() failed
    ");    
                exit(EXIT_FAILURE);      
            }     
    
            printf("In parent, value = %d
    ", *addr);         
            if (munmap(addr, sizeof(int)) == -1) {       
                fprintf(stderr, "munmap()() failed
    ");      
                exit(EXIT_FAILURE);       
            }        
            exit(EXIT_SUCCESS);
    }
    

    来源:
    Linux 编程接口
    第49章:内存映射,
    作者:迈克尔·凯里斯

    Sources:
    The Linux Programming Interface
    Chapter 49: Memory Mappings,
    Author: Michael Kerrisk

    Linux 系统编程(第三版)
    第 8 章:内存管理,
    作者:罗伯特·洛夫

    Linux System Programming (3rd edition)
    Chapter 8: Memory Management,
    Author: Robert Love

    这篇关于mmap 系统调用中 MAP_ANONYMOUS 标志的目的是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆