477 Stimmen

Was sind RSS und VSZ in der Linux-Speicherverwaltung?

Was sind RSS und VSZ in der Linux-Speicherverwaltung? Wie können beide in einer Multithreading-Umgebung verwaltet und nachverfolgt werden?

709voto

jmh Punkte 8356

RSS ist die Resident Set Size und zeigt an, wie viel Speicher diesem Prozess zugewiesen ist und sich im RAM befindet. Ausgelagerter Speicher ist darin nicht enthalten. Sie umfasst auch Speicher aus gemeinsam genutzten Bibliotheken, sofern sich die Seiten dieser Bibliotheken tatsächlich im Speicher befinden. Er enthält den gesamten Stack- und Heap-Speicher.

VSZ ist die Größe des virtuellen Speichers. Sie umfasst den gesamten Speicher, auf den der Prozess zugreifen kann, einschließlich des ausgelagerten Speichers, des zugewiesenen, aber nicht verwendeten Speichers und des Speichers aus gemeinsamen Bibliotheken.

Wenn also Prozess A eine 500K-Binärdatei hat und mit 2500K gemeinsam genutzten Bibliotheken verknüpft ist, 200K Stack/Heap-Zuweisungen hat, von denen 100K tatsächlich im Speicher sind (der Rest ist ausgelagert oder unbenutzt), und er nur 1000K der gemeinsam genutzten Bibliotheken und 400K seiner eigenen Binärdatei geladen hat, dann:

RSS: 400K + 1000K + 100K = 1500K
VSZ: 500K + 2500K + 200K = 3200K

Da ein Teil des Speichers gemeinsam genutzt wird, kann er von vielen Prozessen verwendet werden. Wenn Sie also alle RSS-Werte zusammenzählen, können Sie leicht auf mehr Speicherplatz kommen, als Ihr System hat.

Der zugewiesene Speicher kann auch nicht in RSS sein, bis er tatsächlich vom Programm verwendet wird. Wenn Ihr Programm also im Vorfeld eine Menge Speicher zugewiesen hat und diesen dann im Laufe der Zeit nutzt, kann es sein, dass die RSS steigt und die VSZ gleich bleibt.

Es gibt auch die PSS (Proportional Set Size). Hierbei handelt es sich um ein neueres Maß, das den gemeinsam genutzten Speicher als Anteil des aktuellen Prozesses erfasst. Wenn also zwei Prozesse dieselbe gemeinsam genutzte Bibliothek von vorher verwenden:

PSS: 400K + (1000K/2) + 100K = 400K + 500K + 100K = 1000K

Alle Threads teilen sich denselben Adressraum, so dass RSS, VSZ und PSS für jeden Thread mit allen anderen Threads des Prozesses identisch sind. Verwenden Sie ps oder top, um diese Informationen unter Linux/Unix anzuzeigen.

Das ist noch lange nicht alles. Wenn Sie mehr erfahren möchten, lesen Sie die folgenden Referenzen:

Siehe auch:

61voto

caf Punkte 224189

RSS steht für Resident Set Size (physisch residenter Speicher - dieser belegt derzeit Platz im physischen Speicher des Rechners), und VSZ für Virtual Memory Size (zugewiesener Adressraum - dieser verfügt über Adressen, die in der Speicherabbildung des Prozesses zugewiesen sind, hinter denen sich aber nicht unbedingt ein tatsächlicher Speicher befindet).

Beachten Sie, dass in der heutigen Zeit, in der virtuelle Maschinen alltäglich sind, der physische Speicher aus Sicht der Maschine nicht unbedingt der tatsächliche physische Speicher sein muss.

42voto

Minimales lauffähiges Beispiel

Damit dies sinnvoll ist, müssen Sie die Grundlagen des Auslagerns verstehen: Wie funktioniert das x86-Paging? und insbesondere, dass das Betriebssystem virtuellen Speicher über Seitentabellen / seine interne Speicherbuchführung (VSZ virtueller Speicher) zuweisen kann, bevor es tatsächlich über einen Backup-Speicher im RAM oder auf der Festplatte verfügt (RSS residenter Speicher).

Um dies in Aktion zu beobachten, erstellen wir ein Programm, das:

  • weist mehr RAM zu als unser physischer Speicher mit mmap
  • schreibt ein Byte auf jede Seite, um sicherzustellen, dass jede dieser Seiten aus dem nur virtuellen Speicher (VSZ) in den tatsächlich verwendeten Speicher (RSS) übergeht
  • prüft den Speicherverbrauch des Prozesses mit einer der unter genannten Methoden: Speichernutzung des aktuellen Prozesses in C

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

typedef struct {
    unsigned long size,resident,share,text,lib,data,dt;
} ProcStatm;

/* https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c/7212248#7212248 */
void ProcStat_init(ProcStatm *result) {
    const char* statm_path = "/proc/self/statm";
    FILE *f = fopen(statm_path, "r");
    if(!f) {
        perror(statm_path);
        abort();
    }
    if(7 != fscanf(
        f,
        "%lu %lu %lu %lu %lu %lu %lu",
        &(result->size),
        &(result->resident),
        &(result->share),
        &(result->text),
        &(result->lib),
        &(result->data),
        &(result->dt)
    )) {
        perror(statm_path);
        abort();
    }
    fclose(f);
}

int main(int argc, char **argv) {
    ProcStatm proc_statm;
    char *base, *p;
    char system_cmd[1024];
    long page_size;
    size_t i, nbytes, print_interval, bytes_since_last_print;
    int snprintf_return;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 0x10000;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }
    if (argc < 3) {
        print_interval = 0x1000;
    } else {
        print_interval = strtoull(argv[2], NULL, 0);
    }
    page_size = sysconf(_SC_PAGESIZE);

    /* Allocate the memory. */
    base = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );
    if (base == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Write to all the allocated pages. */
    i = 0;
    p = base;
    bytes_since_last_print = 0;
    /* Produce the ps command that lists only our VSZ and RSS. */
    snprintf_return = snprintf(
        system_cmd,
        sizeof(system_cmd),
        "ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == \"%ju\") print}'",
        (uintmax_t)getpid()
    );
    assert(snprintf_return >= 0);
    assert((size_t)snprintf_return < sizeof(system_cmd));
    bytes_since_last_print = print_interval;
    do {
        /* Modify a byte in the page. */
        *p = i;
        p += page_size;
        bytes_since_last_print += page_size;
        /* Print process memory usage every print_interval bytes.
         * We count memory using a few techniques from:
         * https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c */
        if (bytes_since_last_print > print_interval) {
            bytes_since_last_print -= print_interval;
            printf("extra_memory_committed %lu KiB\n", (i * page_size) / 1024);
            ProcStat_init(&proc_statm);
            /* Check /proc/self/statm */
            printf(
                "/proc/self/statm size resident %lu %lu KiB\n",
                (proc_statm.size * page_size) / 1024,
                (proc_statm.resident * page_size) / 1024
            );
            /* Check ps. */
            puts(system_cmd);
            system(system_cmd);
            puts("");
        }
        i++;
    } while (p < base + nbytes);

    /* Cleanup. */
    munmap(base, nbytes);
    return EXIT_SUCCESS;
}

GitHub vorgelagert .

Kompilieren und ausführen:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
sudo dmesg -c
./main.out 0x1000000000 0x200000000
echo $?
sudo dmesg

où :

  • 0x1000000000 == 64GiB: 2x der physische RAM meines Computers von 32GiB
  • 0x200000000 == 8GiB: druckt den Speicher alle 8GiB, also sollten wir 4 Ausdrucke vor dem Absturz bei etwa 32GiB bekommen
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory : für Linux erforderlich, damit wir einen mmap-Aufruf machen können, der größer ist als der physische RAM: Maximaler Speicher, den malloc zuweisen kann

Programmausgabe:

extra_memory_committed 0 KiB
/proc/self/statm size resident 67111332 768 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 1648

extra_memory_committed 8388608 KiB
/proc/self/statm size resident 67111332 8390244 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 8390256

extra_memory_committed 16777216 KiB
/proc/self/statm size resident 67111332 16778852 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 16778864

extra_memory_committed 25165824 KiB
/proc/self/statm size resident 67111332 25167460 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 25167472

Killed

Status der Beendigung:

137

die durch die 128 + Signalnummer-Regel bedeutet, dass wir die Signalnummer 9 die man 7 signal sagt, ist SIGKILL die vom Linux-System gesendet wird. Out-of-Memory-Killer .

Interpretation der Ausgabe:

  • Der virtuelle Speicher VSZ bleibt konstant bei printf '0x%X\n' 0x40009A4 KiB ~= 64GiB ( ps Werte sind in KiB) nach der mmap.
  • Der "tatsächliche Speicherverbrauch" von RSS steigt nur langsam, wenn wir die Seiten berühren. Zum Beispiel:
    • auf dem ersten Druck, haben wir extra_memory_committed 0 , was bedeutet, dass wir noch keine Seiten angefasst haben. RSS ist eine kleine 1648 KiB der für den normalen Programmstart wie Textbereich, Globals usw. zugewiesen wurde.
    • auf dem zweiten Ausdruck haben wir geschrieben an 8388608 KiB == 8GiB Seitenwert. Infolgedessen stieg RSS um genau 8GIB auf 8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS steigt in 8-GiB-Schritten weiter an. Der letzte Ausdruck zeigt etwa 24 GiB Speicher an, und bevor 32 GiB gedruckt werden konnten, beendete der OOM-Killer den Prozess

Siehe auch: https://unix.stackexchange.com/questions/35129/need-explanation-on-resident-set-size-virtual-size

OOM-Killer-Protokolle

Unser dmesg Befehle haben die OOM-Killer-Protokolle angezeigt.

Um eine genaue Interpretation dieser wurde gebeten:

Die allererste Zeile des Protokolls lautete:

[ 7283.479087] mongod invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

Wir sehen also, dass interessanterweise der MongoDB-Daemon, der auf meinem Laptop immer im Hintergrund läuft, den OOM-Killer zuerst ausgelöst hat, vermutlich als das arme Ding versuchte, Speicher zuzuweisen.

Der OOM-Killer tötet jedoch nicht unbedingt denjenigen, der ihn geweckt hat.

Nach dem Aufruf gibt der Kernel eine Tabelle mit Prozessen aus, die die oom_score :

[ 7283.479292] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[ 7283.479303] [    496]     0   496    16126        6   172032      484             0 systemd-journal
[ 7283.479306] [    505]     0   505     1309        0    45056       52             0 blkmapd
[ 7283.479309] [    513]     0   513    19757        0    57344       55             0 lvmetad
[ 7283.479312] [    516]     0   516     4681        1    61440      444         -1000 systemd-udevd

und weiter vorne sehen wir, dass unser eigenes kleines main.out beim letzten Aufruf tatsächlich getötet wurde:

[ 7283.479871] Out of memory: Kill process 15665 (main.out) score 865 or sacrifice child
[ 7283.479879] Killed process 15665 (main.out) total-vm:67111332kB, anon-rss:92kB, file-rss:4kB, shmem-rss:30080832kB
[ 7283.479951] oom_reaper: reaped process 15665 (main.out), now anon-rss:0kB, file-rss:0kB, shmem-rss:30080832kB

Dieses Protokoll erwähnt die score 865 die dieser Prozess hatte, vermutlich den höchsten (schlechtesten) OOM-Killer-Wert, wie unter erwähnt: https://unix.stackexchange.com/questions/153585/how-does-the-oom-killer-decide-which-process-to-kill-first

Interessant ist auch, dass offenbar alles so schnell ging, dass, bevor der freigegebene Speicher verbucht wurde, die oom wurde erneut durch die DeadlineMonitor Prozess:

[ 7283.481043] DeadlineMonitor invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

und dieses Mal hat das einen Chromium-Prozess beendet, der normalerweise der normale Speicherfresser meines Computers ist:

[ 7283.481773] Out of memory: Kill process 11786 (chromium-browse) score 306 or sacrifice child
[ 7283.481833] Killed process 11786 (chromium-browse) total-vm:1813576kB, anon-rss:208804kB, file-rss:0kB, shmem-rss:8380kB
[ 7283.497847] oom_reaper: reaped process 11786 (chromium-browse), now anon-rss:0kB, file-rss:0kB, shmem-rss:8044kB

Getestet unter Ubuntu 19.04, Linux-Kernel 5.0.0.

Linux-Kernel-Dokumente

https://github.com/torvalds/linux/blob/v5.17/Documentation/filesystems/proc.rst hat einige Punkte. Der Begriff "VSZ" wird dort nicht verwendet, aber "RSS", und es gibt nichts allzu Erhellendes (Überraschung?!)

Anstelle von VSZ scheint der Kernel den Begriff VmSize die z. B. auf /proc/$PID/status .

Einige Zitate von Interesse:

Die erste dieser Zeilen zeigt die gleichen Informationen an, die auch für das Mapping in /proc/PID/maps angezeigt werden. Die folgenden Zeilen zeigen die Größe der Abbildung (size); die Größe jeder Seite, die beim Sichern eines VMAs zugewiesen wird (KernelPageSize), was in der Regel mit der Größe in den Seitentabelleneinträgen übereinstimmt; die Seitengröße, die von der MMU beim Sichern eines VMAs verwendet wird (in den meisten Fällen gleich wie KernelPageSize); den Anteil der Abbildung, der sich derzeit im RAM befindet (RSS); den proportionalen Anteil des Prozesses an dieser Abbildung (PSS); und die Anzahl der sauberen und schmutzigen gemeinsamen und privaten Seiten in der Abbildung.

Die "Proportional Set Size" (PSS) eines Prozesses ist die Anzahl der Seiten, die er im Speicher hat, wobei jede Seite durch die Anzahl der Prozesse geteilt wird, die sie gemeinsam nutzen. Wenn also ein Prozess 1000 Seiten für sich allein hat und 1000 mit einem anderen Prozess teilt, beträgt seine PSS 1500.

Beachten Sie, dass auch eine Seite, die Teil einer MAP_SHARED-Zuordnung ist, aber nur ein einziges pte zugeordnet hat, d. h. derzeit von nur einem Prozess verwendet wird, als privat und nicht als gemeinsam genutzt gilt.

Wir können also ein paar mehr Dinge erraten:

  • Gemeinsame Bibliotheken, die von einem einzelnen Prozess verwendet werden, erscheinen in RSS, wenn mehr als ein Prozess sie hat, dann nicht
  • PSS wurde von jmh erwähnt und hat einen proportionaleren Ansatz zwischen "ich bin der einzige Prozess, der die gemeinsam genutzte Bibliothek besitzt" und "es gibt N Prozesse, die die gemeinsam genutzte Bibliothek besitzen, also besitzt jeder im Durchschnitt Speicher/N"

13voto

Premraj Punkte 65511

VSZ - Virtuelle Satzgröße

  • Die Virtual Set Size ist eine Speichergröße, die einem Prozess (Programm) bei der ersten Ausführung zugewiesen wird. Der Virtual Set Size Speicher ist einfach eine Zahl, die angibt, wie viel Speicher ein Prozess für seine Ausführung zur Verfügung hat.

RSS - Residenter Satz Größe (eine Art RAM)

  • Im Gegensatz zu VSZ ( Virtual Set Size ) ist RSS der von einem Prozess aktuell genutzte Speicher. Dies ist eine tatsächliche Zahl in Kilobytes, die angibt, wie viel RAM der aktuelle Prozess verwendet.

Quelle

7voto

Anugraha Sinha Punkte 589

Ich denke, es wurde bereits viel über RSS und VSZ gesagt. Aus der Sicht eines Administrators/Programmierers/Benutzers mache ich mir beim Entwerfen/Codieren von Anwendungen mehr Sorgen um die RSZ (Residenter Speicher), denn wenn man immer mehr Variablen (gehäuft) zieht, wird dieser Wert in die Höhe schießen. Versuchen Sie ein einfaches Programm, um eine malloc-basierte Speicherzuweisung in einer Schleife zu erstellen, und stellen Sie sicher, dass Sie Daten in diesen malloc-Speicher füllen. RSS steigt weiter an. Was VSZ betrifft, so ist es eher eine virtuelle Speicherzuordnung, die Linux vornimmt, und eine seiner Kernfunktionen, die von konventionellen Betriebssystemkonzepten abgeleitet ist. Die VSZ-Verwaltung erfolgt durch die virtuelle Speicherverwaltung des Kernels. Weitere Informationen über VSZ finden Sie in Robert Loves Beschreibung von mm_struct und vm_struct, die Teil der grundlegenden task_struct-Datenstruktur im Kernel sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X