Introduction To mmap(): Anonymous Memory

mmap(): An Anonymous (Private) Mapping

Building the situation from Lazy Allocation, Demand Paging, And Overcommit

  • Mapping (contents of it) not backed from anywhere (a file, say) ⟶ anonymous mapping (MAP_ANONYMOUS)

  • Mapping is not visible in another address space/process ⟶ private mapping (MAP_PRIVATE)

  • We want the allocated memory to be readable and writable ⟶ PROT_READ|PROT_WRITE

#include <sys/mman.h>
#include <stddef.h>
#include <stdio.h>

int main()
{
    void* memory = mmap(
        NULL,                                          // <-- (addr) let kernel choose address
        16*1024*1024,                                  // <-- (length) 16 MiB *virtually contiguous* memory
        PROT_READ|PROT_WRITE,                          // <-- (prot) memory access protection
        MAP_ANONYMOUS|MAP_PRIVATE,                     // <-- (flags) anon, copy-on-write (we don't share anyway though)
        -1,                                            // <-- (fd) no fd, this is an anonymous mapping
        0                                              // <-- (offset) no offset, this is an anonymous mapping
    );
    if (memory == MAP_FAILED) {                        // <-- MAP_FAILED is -1 (as every syscall error)
        perror("mmap");
        return 1;
    }

    *(((char*)memory)+16) = 'a';                       // <-- memory access in first page of mapping
                                                       //     will cause page to be allocated

    munmap(memory, 16*1024*1024);                      // <-- technically not necessary; done anyway at exit

    return 0;
}

Step By Step: From Unpopulated To Populated

  • Modify above program to …

    • output its PID

    • wait before and after memory access

cout << getpid() << '\n';
...
cin.get();
*(((char*)memory)+16) = 'a';                       // <-- memory access in first page of mapping
                                                   //     will cause page to be allocated
cin.get();
...
$ ./code/mmap-anon-interactive
216234

Unpopulated Mapping: /proc/PID/maps, /proc/PID/smaps

  • Peek into /proc/PID/maps

  • Talk about program loading (mappings with a program file, or a shared library) ⟶ later

  • Find our mapping (16 MiB)

$ cat /proc/216234/maps
...
7f1571c00000-7f1572c00000 rw-p 00000000 00:00 0
...
  • Is that mapping populated?

  • ⟶ Peek into /proc/PID/smaps (contains much more information)

  • Search for 7f1571c00000-7f1572c00000 (or whatever maps shows)

  • Rss (from man -s 5 proc): 0 bytes allocated from that mapping

$ less /proc/216234/smaps
...
7f1571c00000-7f1572c00000 rw-p 00000000 00:00 0
Size:              16384 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                   0 kB                            # <-- not allocated
Pss:                   0 kB
Pss_Dirty:             0 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:            0 kB
Anonymous:             0 kB
KSM:                   0 kB
LazyFree:              0 kB
AnonHugePages:         0 kB
ShmemPmdMapped:        0 kB
FilePmdMapped:         0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
Locked:                0 kB
THPeligible:           0
ProtectionKey:         0
VmFlags: rd wr mr mw me ac sd
...

Lazy Allocation, And Rss

  • Move program past memory access (hit return)

  • ⟶ Et voila: one page allocated

$ less /proc/216234/smaps
...
7f1571c00000-7f1572c00000 rw-p 00000000 00:00 0
Size:              16384 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                   4 kB                            # <-- one page allocated
...