linuxmemory-managementshared-memorypagingpmap

Interpreting pmap shared memory size output


I am trying to understand the shared memory output value of pmap -d <pid>. Towards this I have done an exercise wherein first I have created 2 shared memory segments.

#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;

int main(int argc,char *argv[])
{
        if ( argc < 2 ) {
                cout<<endl<<"Usage : "<<argv[0]<<" Key(numeric)"<<endl<<endl;
                exit(EXIT_FAILURE);
        }

        // ftok to generate unique key
        key_t key = key_t(atoi(argv[1]));

        // shmget returns an identifier in shmid
        int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
        if (shmid == -1) {
                perror("Shared memory");
                exit(EXIT_FAILURE);
        }

        cout<<endl<<"Shared memory created with id : "<<shmid<<endl<<endl;

        return 0;
}

./CreShm.exe 1000
./CreShm.exe 2000


0x000003e8 32816      soumajit   666        1024       1                       
0x000007d0 32817      soumajit   666        1024       1 

Next I have written a program to attach to the 2 shared memory segments.

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;

int main(int argc,char *argv[])
{
        if ( argc < 3 ) {
                cout<<endl<<"Usage : "<<argv[0]<<" Key1(numeric)"<< " Key2(numeric)"<<endl<<endl;
                exit(EXIT_FAILURE);
        }

        key_t key ;
        int shmid ;
        struct shmseg *shmp;

        key = key_t(atoi(argv[1]));

        // shmget returns an identifier in shmid
        shmid = shmget(key, 1024, 0644 | IPC_CREAT);
        if (shmid == -1) {
                perror("Shared memory");
                exit(EXIT_FAILURE);
        }

        char* str1;
        // shmat to attach to shared memory
        str1 = (char*)shmat(shmid, (void*)0, 0);
        if (str1 == (void *) -1) {
                perror("Shared memory not attached!!");
                exit(EXIT_FAILURE);
        }

        cout<<endl<<"Attached to 1st shared memory segment!!"<<endl;

        key = key_t(atoi(argv[2]));

        // shmget returns an identifier in shmid
        shmid = shmget(key, 1024, 0644 | IPC_CREAT);
        if (shmid == -1) {
                perror("Shared memory");
                exit(EXIT_FAILURE);
        }

        char* str2;
        // shmat to attach to shared memory
        str2 = (char*)shmat(shmid, (void*)0, 0);
        if (str2 == (void *) -1) {
                perror("Shared memory not attached!!");
                exit(EXIT_FAILURE);
        }

        cout<<endl<<"Attached to 2nd shared memory segment!!"<<endl;

        while(1) {

                sleep(1);
        }

        return 0;
}

Then I have generated output of pmap command.

14652:   ./ShmDirectConnector.exe 1000 2000
Address           Kbytes Mode  Offset           Device    Mapping
000055c88ba97000       4 r-x-- 0000000000000000 008:00002 ShmDirectConnector.exe
000055c88bc98000       4 r---- 0000000000001000 008:00002 ShmDirectConnector.exe
000055c88bc99000       4 rw--- 0000000000002000 008:00002 ShmDirectConnector.exe
000055c88c64d000     132 rw--- 0000000000000000 000:00000   [ anon ]
00007f20b949c000      92 r-x-- 0000000000000000 008:00002 libgcc_s.so.1
00007f20b94b3000    2044 ----- 0000000000017000 008:00002 libgcc_s.so.1
00007f20b96b2000       4 r---- 0000000000016000 008:00002 libgcc_s.so.1
00007f20b96b3000       4 rw--- 0000000000017000 008:00002 libgcc_s.so.1
00007f20b96b4000    1652 r-x-- 0000000000000000 008:00002 libm-2.27.so
00007f20b9851000    2044 ----- 000000000019d000 008:00002 libm-2.27.so
00007f20b9a50000       4 r---- 000000000019c000 008:00002 libm-2.27.so
00007f20b9a51000       4 rw--- 000000000019d000 008:00002 libm-2.27.so
00007f20b9a52000    1948 r-x-- 0000000000000000 008:00002 libc-2.27.so
00007f20b9c39000    2048 ----- 00000000001e7000 008:00002 libc-2.27.so
00007f20b9e39000      16 r---- 00000000001e7000 008:00002 libc-2.27.so
00007f20b9e3d000       8 rw--- 00000000001eb000 008:00002 libc-2.27.so
00007f20b9e3f000      16 rw--- 0000000000000000 000:00000   [ anon ]
00007f20b9e43000    1508 r-x-- 0000000000000000 008:00002 libstdc++.so.6.0.25
00007f20b9fbc000    2048 ----- 0000000000179000 008:00002 libstdc++.so.6.0.25
00007f20ba1bc000      40 r---- 0000000000179000 008:00002 libstdc++.so.6.0.25
00007f20ba1c6000       8 rw--- 0000000000183000 008:00002 libstdc++.so.6.0.25
00007f20ba1c8000      16 rw--- 0000000000000000 000:00000   [ anon ]
00007f20ba1cc000     156 r-x-- 0000000000000000 008:00002 ld-2.27.so
00007f20ba3cd000      24 rw--- 0000000000000000 000:00000   [ anon ]
00007f20ba3f1000       4 rw-s- 0000000000000000 000:00001   [ shmid=0x8031 ]
00007f20ba3f2000       4 rw-s- 0000000000000000 000:00001   [ shmid=0x8030 ]
00007f20ba3f3000       4 r---- 0000000000027000 008:00002 ld-2.27.so
00007f20ba3f4000       4 rw--- 0000000000028000 008:00002 ld-2.27.so
00007f20ba3f5000       4 rw--- 0000000000000000 000:00000   [ anon ]
00007ffdb0f9f000     132 rw--- 0000000000000000 000:00000   [ stack ]
00007ffdb0fe1000      12 r---- 0000000000000000 000:00000   [ anon ]
00007ffdb0fe4000       4 r-x-- 0000000000000000 000:00000   [ anon ]
ffffffffff600000       4 --x-- 0000000000000000 000:00000   [ anon ]
mapped: 14000K    writeable/private: 356K    shared: 8K

My question is even though the size of 2 shared memory segments add to 2048 bytes, why does the pmap output show 8K ? Is it because of paging ? If it is attributed to paging, wouldn't 1 page have been sufficient to accommodate both the shared memory segments ? Kindly guide me about the underlying reason.

getconf PAGESIZE output in my system shows 4096 ?


Solution

  • Your intuition about the page size is correct. The shmget man page says:

    A new shared memory segment, with size equal to the value of size rounded up to a multiple of PAGE_SIZE, is created if ...

    (So technically this means you did not allocate a 1kb shared memory segment, the actual segment size was rounded up at creation time to 4kb.)

    I suspect the motivation is to avoid false sharing (and false corruption). If I have two 1kb shared memory segments, and only gave one of them to a process, I would be very surprised if that process could corrupt or influence the contents of the other shared memory segment.

    To keep the segments separate, and separately mappable, each segment must be within its own page-granularity sized region, so the OS can leverage the page-granularity access controls.