Verwirrung über PSS in /proc/pid/maps

Verwirrung über PSS in /proc/pid/maps

Ich fand eine tolle Erklärung zu Smaps von Infos zu smaps

Nach meinem Verständnis dachte ich, dass

shared_clean + shared_dirty + private_clean + private_dirty = rss

Um dies zu überprüfen, habe ich ein Programm geschrieben:

void sa();
int main(int argc,char *argv[])
{
    sa();
    sleep(1000);
}

void sa()
{
   char *pi=new char[1024*1024*10];
   for(int i=0;i<4;++i) {   //dirty should be 4M
        for(int j=0;j<1024*1024;++j){
                *pi='o';
                pi++;
        }
   }
   int cnt;
   for(int i=0;i<6;++i) {   //clean should be 6M
        for(int j=0;j<1024*1024;++j){
                cnt+=*pi;
                pi++;
        }
   }
   printf("%d",cnt);
}

Aber zu meiner Überraschung /proc/pid/smapslautet es:

09b69000-09b8c000 rw-p 00000000 00:00 0 [heap]
...
Size:           10252 kB
Rss:            10252 kB
Pss:             4108 kB //<----I thought it should be 10M
Shared_Clean:       0 kB
Shared_Dirty:       0 kB
Private_Clean:      0 kB //<----I thought it should be 6M
Private_Dirty:   4108 kB
Referenced:      4108 kB
Swap:               0 kB
KernelPageSize:     4 kB
MMUPageSize:        4 kB

Stimmt etwas mit meinem Verständnis nicht?


gemäß der Antwort von Mat,

Die Seiten in den 6M, die Sie gerade lesen, können nicht wirklich als sauber betrachtet werden. Eine saubere Seite ist eine Seite, die mit ihrem Backing Store (was auch immer das ist, Swap, eine Datei usw.) synchronisiert ist.

.

Ich habe den Code mit mmap neu geschrieben, dieses Mal ist das Ergebnis wie erwartet :)

Erstellen Sie zuerst eine Dummy-Datei:

time dd if=/dev/zero of=test.bin bs=30000000 count=1

neuer Code:

void sa(char *pi)
{
   for(int i=0;i<4;++i) {
        for(int j=0;j<1024*1024;++j){
                *pi='a';
                pi++;
        }
   }
   //just to use it to avoid the following code will not optimized off by the compiler 
   int dummycnt=0;
   for(int i=0;i<6;++i) {
        for(int j=0;j<1024*1024;++j){
                dummycnt+=*pi;
                pi++;
        }
   }
   printf("%d",dummycnt);
}


int main()
{
       int fd  = open("./test.bin",O_RDWR);
       char *p = (char *)mmap(0,
                      1024*1024*10, //10M
                      PROT_READ|PROT_WRITE,
                      MAP_SHARED,
                      fd,
                      0);
       sa(p);
       sleep(10000);
} 

Katze /proc/pid/smaps:

b6eae000-b78ae000 rw-s 00000000 08:05 134424     ..../test.bin
Size:              10240 kB
Rss:               10240 kB
Pss:               10240 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:      6144 kB
Private_Dirty:      4096 kB
Referenced:        10240 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

Antwort1

Zunächst einmal weist Ihr Code ein undefiniertes Verhalten auf ( cntwird ohne Initialisierung verwendet, dasselbe gilt für die oberen 6M, die Sie ohne Initialisierung lesen). Stellen Sie also sicher, dass Ihr Compiler tatsächlich Anweisungen ausgibt, die mit Ihrem Code übereinstimmen: Das muss er nicht. (Ich gehe davon aus, dass Sie das überprüft haben.)

Die Seiten in der 6M, die Sie gerade lesen, können nicht wirklich als sauber betrachtet werden. Eine saubere Seite ist eine Seite, die mit ihrem Sicherungsspeicher (was auch immer das ist, Swap, eine Datei usw.) synchronisiert ist. Diese Seiten haben nichts, das sie stützt.
Sie sind auch nicht wirklich schmutzig im üblichen Sinne – schließlich wurden sie nicht geändert.

Was passiert hier also? Alle Seiten im 6M-Block, den Sie gerade lesen, werden auf dieselbe Seite abgebildet, und diese Seite ist die „Nullseite“ (d. h. eine gemeinsam genutzte Seite (zumindest auf x86), die 4 KB Nullbyte enthält).

Wenn der Kernel einen Seitenfehler auf einer nicht zugeordneten anonymen Seite erhält und dieser Fehler ein Lesevorgang ist, wird eine Nullseite zugeordnet (jedes Mal dieselbe Seite). (Dies steht in do_anonymous_pagein mm/memory.c.)
Dies ist keine „normale“ Zuordnung (im Sinne) und wird in den Feldern nicht als gemeinsam genutzt oder privat vm_normal_pagegezählt ( in überspringt „spezielle“ Seiten vollständig). Es wird jedoch in RSS und Größe gezählt: Aus der Perspektive des Adressraums existieren diese virtuellen Seiten und wurden „verwendet“. Wenn Sie anfangen, eine Seite in diesem Bereich zu ändern (auf sie zu schreiben), wird eine richtige, normale Zuordnung mit einer anonymen Seite erstellt (interessanterweise in diesem speziellen Fall nullinitialisiert – sie wird nicht nullinitialisiert, wenn die vorherige (nicht normale/falsche) Zuordnung nicht auf die Nullseite erfolgte). (Siehe in .) An diesem Punkt wird die erwartete Anzeige angezeigt.smapssmaps_pte_entryfs/proc/task_mmu.c
do_wp_pagemm/memory.csmaps

Bitte beachten Sie, dass weder in C, POSIX noch sonst wo garantiert wird, dass diese Seiten Nullen enthalten. Darauf können Sie sich nicht verlassen. (Unter Linux können Sie sich eigentlich auch nicht darauf verlassen – so ist es derzeit implementiert, aber es könnte sich möglicherweise ändern.)

verwandte Informationen