Mmap

در رایانش، mmap(2)‎ (برگرفته از memory map) یک فراخوان سیستمی یونیکسی سازگار با استاندارد پازیکس است که پرونده‌ها و دستگاه‌ها را در حافظه سیستم نگاشت (به انگلیسی: map) می‌کند. این فراخوان سیستمی، روشی برای انجام دادن عمل ورودی/خروجی اطلاعات در فایل‌های حافظه-نگاشت را فراهم می‌کند. فراخوان سیستمی mmap، اساساً کارش را به صورت صفحه‌بندی نیازی انجام می‌دهد، چرا که در ابتدا تمام محتوایات فایل از هارد دیسک خوانده نمی‌شود و از حافظه فیزیکی RAM استفاده نمی‌شود، تنها هر جا که نیاز بود، اطلاعات از هارد دیسک خوانده شده و به RAM آورده می‌شوند. به عبارت دیگر، اطلاعات تا زمانی که درخواست نشده‌اند وارد RAM نمی‌شوند و عمل واقعی خواندن اطلاعات از روی دیسک به صورت «تنبل‌گونه» صورت می‌گیرد. پس از اینکه دیگر نیازی به حافظه نبود، باید فراخوان سیستمی دیگری به نام munmap(2)‎ اجرا شود و اشاره‌گر به ناحیه‌ای از حافظه که اطلاعات در آنجا قرار داشته‌اند، به عنوان آرگومان برای آن ارسال شود. به کمک فراخوان سیستمی دیگری به نام mprotect(2)‎ می‌توان از اطلاعات در حافظه محافظت کرد و به کمک فراخوان سیستمی دیگری به نام madvise(2)‎ هم می‌توان رفتارهای خاص در مورد آن ناحیه از حافظه را کنترل کرد. در سیستم‌عامل‌های لینوکس، مک اواس ده و خانواده بی‌اس‌دی، فراخوان سیستمی mmap می‌تواند عمل نگاشت را به روش‌های گوناگونی انجام دهد.

تاریخچه

mmap و دیگر فراخوان‌های مربوطه، اولین بار در بی‌اس‌دی یونیکس طراحی شدند. واسط کاربری آنها در راهنمای سیستمی 4.2BSD تشریح شده است، حتی با اینکه هیچکدام از آن فراخوان‌ها نه در آن نسخه و نه در 4.3BSD پیاده‌سازی نشده بودند. سان مایکروسیستمز آنها را در سیستم‌عامل سان‌اواس خود پیاده‌سازی کرده بود. توسعه‌دهندگان بی‌اس‌دی در دانشگاه برکلی از سان درخواست کردند که پیاده‌سازی mmap را برای آنها ارسال کند، اما سان هرگز این کار را انجام نداد. 4.3BSD-Reno به همراه یک پیاده‌سازی از mmap عرضه می‌شد که مبتنی بر سیستم حافظه مجازی ماخ طراحی شده بود.

مثال از نحوه استفاده

#include <sys/types.h>#include <sys/mman.h>#include <err.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>
 
int main(void){
        const char str1[] = "string 1";
        const char str2[] = "string 2";
        int parpid = getpid(), childpid;
        int fd = -1;
        char *anon, *zero;
 
        if ((fd = open("/dev/zero", O_RDWR, 0)) == -1)
                err(1, "open");
 
        anon = (char*)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
        zero = (char*)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
 
        if (anon == MAP_FAILED || zero == MAP_FAILED)
                errx(1, "either mmap");
 
        strcpy(anon, str1);
        strcpy(zero, str1);
 
        printf("PID %d:\tanonymous %s, zero-backed %s\n", parpid, anon, zero);
        switch ((childpid = fork())) {
        case -1:
                err(1, "fork");
                /* NOTREACHED */
 
        case 0:
                childpid = getpid();
                printf("PID %d:\tanonymous %s, zero-backed %s\n", childpid, anon, zero);
                sleep(3);
 
                printf("PID %d:\tanonymous %s, zero-backed %s\n", childpid, anon, zero);
                munmap(anon, 4096);
                munmap(zero, 4096);
                close(fd);
                return (EXIT_SUCCESS);
        }
 
        sleep(2);
        strcpy(anon, str2);
        strcpy(zero, str2);
 
        printf("PID %d:\tanonymous %s, zero-backed %s\n", parpid, anon, zero);
        munmap(anon, 4096);
        munmap(zero, 4096);
        close(fd);
        return (EXIT_SUCCESS);}