Search code examples
cmemorylinux-kernelmmap

Understanding memory allocations


I'm trying to understand "how memory works". As far as I understand the OS (Linux in my case) when calling mmap to create MAP_ANONYMOUS mapping it creates:

mmap() creates a new mapping in the virtual address space of the calling process

As far as I know virtyal address space of a process may exceed tge actual physical memory available.

Also as far as I know the actual mapping to a physical memory occurs when CPU triggers page fault when it tries to access to a memory page that is not in page table yet.

OS catches the page fault and creates an entry in a page directory.

What should happen if I mmaped some anonymous memory (but did not touch any of the pages), then other processess exhausted all the physical memory and then I try to use one of the pages mmaped (I have swap disabled)?

CPU should trigger page fault and then try to create an entry in a page direcrory. But since no physical memory left it will not be able to do so...


Solution

  • To use mmap (MAP_ANONYMOUS) or malloc changes nothing in your case, if you dont have enough free memory mmap returns MAP_FAILED and malloc returns NULL

    If I use that program :

    #include <sys/mman.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char ** argv)
    {
      int n = atoi(argv[1]);
      void * m;
    
      if (argc == 1) {
        m = mmap(NULL, n*1024*1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    
        if (m == MAP_FAILED) {
          puts("ko");
          return 0;
        }
      }
      else {
        m = malloc(n*1024*1024);
        if (m == 0) {
          puts("ko");
          return 0;
        }
      }
    
      puts("ok");
      getchar();
    
      char * p = (char *) m;
      char * sup = p + n*1024*1024;
    
      while (p < sup) {
        *p = 0;
        p += 512;
      }
    
      puts("done");
      getchar();
    
      return 0;
    }
    

    I am on a raspberrypi with 1Gb of memory and a swap of 100Mo, the memory is already used by chromium because I am on SO

    proc/meminfo gives :

    MemTotal:         949448 kB
    MemFree:          295008 kB
    MemAvailable:     633560 kB
    Buffers:           39296 kB
    Cached:           360372 kB
    SwapCached:            0 kB
    Active:           350416 kB
    Inactive:         260960 kB
    Active(anon):     191976 kB
    Inactive(anon):    41908 kB
    Active(file):     158440 kB
    Inactive(file):   219052 kB
    Unevictable:           0 kB
    Mlocked:               0 kB
    SwapTotal:        102396 kB
    SwapFree:         102396 kB
    Dirty:               352 kB
    Writeback:             0 kB
    AnonPages:        211704 kB
    Mapped:           215924 kB
    Shmem:             42304 kB
    Slab:              24528 kB
    SReclaimable:      12108 kB
    SUnreclaim:        12420 kB
    KernelStack:        2128 kB
    PageTables:         5676 kB
    NFS_Unstable:          0 kB
    Bounce:                0 kB
    WritebackTmp:          0 kB
    CommitLimit:      577120 kB
    Committed_AS:    1675164 kB
    VmallocTotal:    1114112 kB
    VmallocUsed:           0 kB
    VmallocChunk:          0 kB
    CmaTotal:           8192 kB
    CmaFree:            6796 kB
    

    If I do that :

    pi@raspberrypi:/tmp $ ./a.out 750
    ko
    

    750 is to large, but

    pi@raspberrypi:/tmp $ ./a.out 600 &
    [1] 1525
    pi@raspberrypi:/tmp $ ok
    

    The used memory (top etc) doesn't reflect the 600Mo because I do not read/write in them

    proc/meminfo gives :

    MemTotal:         949448 kB
    MemFree:          282860 kB
    MemAvailable:     626016 kB
    Buffers:           39432 kB
    Cached:           362860 kB
    SwapCached:            0 kB
    Active:           362696 kB
    Inactive:         260580 kB
    Active(anon):     199880 kB
    Inactive(anon):    41392 kB
    Active(file):     162816 kB
    Inactive(file):   219188 kB
    Unevictable:           0 kB
    Mlocked:               0 kB
    SwapTotal:        102396 kB
    SwapFree:         102396 kB
    Dirty:               624 kB
    Writeback:             0 kB
    AnonPages:        220988 kB
    Mapped:           215672 kB
    Shmem:             41788 kB
    Slab:              24788 kB
    SReclaimable:      12296 kB
    SUnreclaim:        12492 kB
    KernelStack:        2136 kB
    PageTables:         5692 kB
    NFS_Unstable:          0 kB
    Bounce:                0 kB
    WritebackTmp:          0 kB
    CommitLimit:      577120 kB
    Committed_AS:    2288564 kB
    VmallocTotal:    1114112 kB
    VmallocUsed:           0 kB
    VmallocChunk:          0 kB
    CmaTotal:           8192 kB
    CmaFree:            6796 kB
    

    And I can again do

    pi@raspberrypi:/tmp $ ./a.out 600 &
    [2] 7088
    pi@raspberrypi:/tmp $ ok
    
    pi@raspberrypi:/tmp $ jobs
    [1]-  stopped                 ./a.out 600
    [2]+  stopped                 ./a.out 600
    pi@raspberrypi:/tmp $ 
    

    Even the total is too large for the memory + swap, /proc/meminfo gives :

    MemTotal:         949448 kB
    MemFree:          282532 kB
    MemAvailable:     626112 kB
    Buffers:           39432 kB
    Cached:           359980 kB
    SwapCached:            0 kB
    Active:           365200 kB
    Inactive:         257736 kB
    Active(anon):     202280 kB
    Inactive(anon):    38320 kB
    Active(file):     162920 kB
    Inactive(file):   219416 kB
    Unevictable:           0 kB
    Mlocked:               0 kB
    SwapTotal:        102396 kB
    SwapFree:         102396 kB
    Dirty:                52 kB
    Writeback:             0 kB
    AnonPages:        223520 kB
    Mapped:           212600 kB
    Shmem:             38716 kB
    Slab:              24956 kB
    SReclaimable:      12476 kB
    SUnreclaim:        12480 kB
    KernelStack:        2120 kB
    PageTables:         5736 kB
    NFS_Unstable:          0 kB
    Bounce:                0 kB
    WritebackTmp:          0 kB
    CommitLimit:      577120 kB
    Committed_AS:    2876612 kB
    VmallocTotal:    1114112 kB
    VmallocUsed:           0 kB
    VmallocChunk:          0 kB
    CmaTotal:           8192 kB
    CmaFree:            6796 kB
    

    If I write in the memory of %1 then stop it I have a lot of swap done on the flash

    pi@raspberrypi:/tmp $ %1
    ./a.out 600
    
    done
    ^Z
    [1]+  stopped                 ./a.out 600
    

    now there is almost no free swap and almost no free memory, /proc/meminfo gives

    MemTotal:         949448 kB
    MemFree:           33884 kB
    MemAvailable:      32544 kB
    Buffers:             796 kB
    Cached:            66032 kB
    SwapCached:        66608 kB
    Active:           483668 kB
    Inactive:         390360 kB
    Active(anon):     462456 kB
    Inactive(anon):   374188 kB
    Active(file):      21212 kB
    Inactive(file):    16172 kB
    Unevictable:           0 kB
    Mlocked:               0 kB
    SwapTotal:        102396 kB
    SwapFree:           3080 kB
    Dirty:                96 kB
    Writeback:             0 kB
    AnonPages:        740984 kB
    Mapped:            61176 kB
    Shmem:             29288 kB
    Slab:              21932 kB
    SReclaimable:       9084 kB
    SUnreclaim:        12848 kB
    KernelStack:        2064 kB
    PageTables:         7012 kB
    NFS_Unstable:          0 kB
    Bounce:                0 kB
    WritebackTmp:          0 kB
    CommitLimit:      577120 kB
    Committed_AS:    2873112 kB
    VmallocTotal:    1114112 kB
    VmallocUsed:           0 kB
    VmallocChunk:          0 kB
    CmaTotal:           8192 kB
    CmaFree:            6796 kB
    

    %1 is still waiting on the getchar, if I do the same for %2 it works but in fact because the process %1 disappear (without message on the shell)

    The behavior is the same if I malloc (giving a second argument to the program)


    See also What is the purpose of MAP_ANONYMOUS flag in mmap system call?