Search code examples
clinuxsystem-callsshared-memorymmap

Observing shared mapped file memory in linux


I'm using mmap syscall to load file memory for reading by several other processes (with flag MAP_SHARED and MAP_POPULATE to load all memory in advance.).

Checking the process memory consumption seems to ignore the fact that the mapped file memory is shared. Each process memory usage contains the entire mapped file in memory according to ps -aux command.

Is there a way to differentiate between shared and private process memory ?


Solution

  • Even if the memory is physically shared, each process has it's own virtual memory mapping and will "consume" an independent addressing space even if mapping the same area - you can see it in the VSIZE column. In any case (even after a malloc()) the kernel will reserve an independent addressing space for each process, but will not immediately allocate the equivalent pages in the backing store.

    As soon as you start reading/writing to the allocated memory, virtual pages are being assigned to the corresponding backing store: the resident set increases correspondingly.

    These pages are "clean" if you just read, "dirty" if you write to them, until they are not synchronized. (see /proc/PID/smaps, /proc documentation, man pmap: this tool let you differentiate shared and private memory, dirty and clean pages)

    MAP_POPULATE option pre-assign all the pages immediately. If the mapping is MAP_PRIVATE the pages are allowed to be kept dirty, until they are not explicitly synchronized with msync(). Dirty pages are cached in RAM, and in fact the available system memory decrease as soon as you use more pages, with private mappings.

    On the other side, using MAP_SHARED, you require to the kernel to keep the virtual pages synchronized (ie, the pages must be clean, as soon as possible, even if asynchronously) with the backing store.

    But with a mapped file the backing store is not memory, but it's the file - as it was swap space. So you have the odd effect that the mapped file is counted as resident set.

    This can be verified observing the content of /proc/PID/status:

    VmRSS                       size of memory portions. It contains the three
                                following parts (VmRSS = RssAnon + RssFile + RssShmem)
    RssAnon                     size of resident anonymous memory
    RssFile                     size of resident file mappings
    RssShmem                    size of resident shmem memory (includes SysV shm,
                                mapping of tmpfs and shared anonymous mappings)
    

    VmRSS is what is usually reported as RSS.

    RSS is not counting physical memory in this case, but the file mapping: the total system memory is mostly unaffected when requesting MAP_SHARED, since mostly no pages are cached (cached, dirty pages would be accounted in RssAnon). They must be flushed to the shared backing store (the file) as soon as possible.

    As you correctly observed, RSS is counted once per process, even if shared. You can find in /proc/PID/smaps another counter, PSS (proportional set size) - see this answer too:

    What does pss mean in /proc/pid/smaps

    The "proportional set size" (PSS) of a process is the count of pages it has in memory, where each page is divided by the number of processes sharing it. So if a process has 1000 pages all to itself, and 1000 shared with one other process, its PSS will be 1500

    One note: You can have shared memory using MAP_SHARED|MAP_POPULATE only using tmpfs - otherwise you will be using a file-based sharing. If you are looking for IPC shared memory, have a look to shmget().

    Tests

    I've verified my statements with a tiny program, which mapped 2 GB from a file with different flags, and then wrote 1/3 of the pages with memset().

    MAP_PRIVATE

    ps -u output:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    xxxx     15767  0.5  4.1 2004216 666944 pts/1  S+   12:54   0:00 ./mm 1
    

    from /proc/PID/smaps:

    7f143e5ec000-7f14b870c000 rw-p 00000000 fd:00 201562609                  /home/xxxx/test/mm.dat
    Size:            2000000 kB
    Rss:              666668 kB
    Pss:              666668 kB
    Shared_Clean:          0 kB
    Shared_Dirty:          0 kB
    Private_Clean:         0 kB
    Private_Dirty:    666668 kB
    Referenced:       666668 kB
    Anonymous:        666668 kB
    AnonHugePages:         0 kB
    Swap:                  0 kB
    KernelPageSize:        4 kB
    MMUPageSize:           4 kB
    Locked:                0 kB
    VmFlags: rd wr mr mw me ac sd 
    

    from /proc/PID/status:

    VmRSS:    666944 kB
    RssAnon:          666560 kB
    RssFile:             384 kB
    RssShmem:              0 kB
    

    MAP_PRIVATE | MAP_POPULATE

    ps -u output:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND 
    xxxx     17045 31.0 12.3 2004216 2000412 pts/1 S+   13:01   0:01 ./mm 2
    

    from /proc/PID/smaps:

    7f14aa983000-7f1524aa3000 rw-p 00000000 fd:00 201562609                  /home/xxxx/test/mm.dat
    Size:            2000000 kB
    Rss:             2000000 kB
    Pss:             2000000 kB
    Shared_Clean:          0 kB
    Shared_Dirty:          0 kB
    Private_Clean:         0 kB
    Private_Dirty:   2000000 kB
    Referenced:      2000000 kB
    Anonymous:       2000000 kB
    AnonHugePages:         0 kB
    Swap:                  0 kB
    KernelPageSize:        4 kB
    MMUPageSize:           4 kB
    Locked:                0 kB
    VmFlags: rd wr mr mw me ac sd 
    

    from /proc/PID/status:

    VmRSS:   2000412 kB
    RssAnon:         2000032 kB
    RssFile:             380 kB
    RssShmem:              0 kB
    

    MAP_SHARED

    ps -u output:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    xxxx     17670 18.0  4.1 2004216 666944 pts/1  S+   13:06   0:00 ./mm 3
    

    from /proc/PID/smaps:

    7f01db018000-7f0255138000 rw-s 00000000 fd:00 201562609                  /home/xxxx/test/mm.dat
    Size:            2000000 kB
    Rss:              666668 kB
    Pss:              666668 kB
    Shared_Clean:          0 kB
    Shared_Dirty:          0 kB
    Private_Clean:    666668 kB
    Private_Dirty:         0 kB
    Referenced:       666668 kB
    Anonymous:             0 kB
    AnonHugePages:         0 kB
    Swap:                  0 kB
    KernelPageSize:        4 kB
    MMUPageSize:           4 kB
    Locked:                0 kB
    VmFlags: rd wr sh mr mw me ms sd 
    

    from /proc/PID/status:

    VmRSS:    666944 kB
    RssAnon:              96 kB
    RssFile:          666848 kB
    RssShmem:              0 kB
    

    MAP_SHARED | MAP_POPULATE

    ps -u output:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    xxxx     18259 16.1 12.3 2004216 2000480 pts/1 S+   13:10   0:00 ./mm 4
    

    from /proc/PID/smaps:

    7ff0d020b000-7ff14a32b000 rw-s 00000000 fd:00 201562609                  /home/xxxx/test/mm.dat
    Size:            2000000 kB
    Rss:             2000000 kB
    Pss:             2000000 kB
    Shared_Clean:          0 kB
    Shared_Dirty:          0 kB
    Private_Clean:   2000000 kB
    Private_Dirty:         0 kB
    Referenced:      2000000 kB
    Anonymous:             0 kB
    AnonHugePages:         0 kB
    Swap:                  0 kB
    KernelPageSize:        4 kB
    MMUPageSize:           4 kB
    Locked:                0 kB
    VmFlags: rd wr sh mr mw me ms sd 
    

    from /proc/PID/status:

    VmRSS:   2000480 kB
    RssAnon:              96 kB
    RssFile:         2000384 kB
    RssShmem:              0 kB
    

    MAP_SHARED | MAP_POPULATE, two instances

    ps -u output:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    xxxx     18259  0.1 12.3 2004216 2000480 pts/1 S    13:10   0:00 ./mm 4
    xxxx     19521  5.8 12.3 2004216 2000480 pts/1 S+   13:19   0:00 ./mm 4
    

    from /proc/PID/smaps, one first PID only:

    7ff0d020b000-7ff14a32b000 rw-s 00000000 fd:00 201562609                  /home/xxxx/test/mm.dat
    Size:            2000000 kB
    Rss:             2000000 kB
    Pss:             1000000 kB
    Shared_Clean:    2000000 kB
    Shared_Dirty:          0 kB
    Private_Clean:         0 kB
    Private_Dirty:         0 kB
    Referenced:      2000000 kB
    Anonymous:             0 kB
    AnonHugePages:         0 kB
    Swap:                  0 kB
    KernelPageSize:        4 kB
    MMUPageSize:           4 kB
    Locked:                0 kB
    VmFlags: rd wr sh mr mw me ms sd 
    

    from /proc/PID/status:

    VmRSS:   2000480 kB
    RssAnon:              96 kB
    RssFile:         2000384 kB
    RssShmem:              0 kB