¿Qué es RSS y VSZ en la gestión de memoria de Linux?

Respuestas:

499

RSS es el tamaño de conjunto residente y se utiliza para mostrar cuánta memoria se asigna a ese proceso y está en la RAM. No incluye la memoria que se intercambia. Incluye memoria de bibliotecas compartidas siempre que las páginas de esas bibliotecas estén realmente en memoria. Incluye toda la memoria de pila y montón.

VSZ es el tamaño de la memoria virtual. Incluye toda la memoria a la que puede acceder el proceso, incluida la memoria intercambiada, la memoria asignada pero no utilizada y la memoria que proviene de bibliotecas compartidas.

Entonces, si el proceso A tiene un binario de 500K y está vinculado a 2500K de bibliotecas compartidas, tiene 200K de asignaciones de pila / montón de las cuales 100K está realmente en la memoria (el resto está intercambiado o sin usar), y solo ha cargado 1000K de las bibliotecas compartidas y 400K de su propio binario entonces:

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

Dado que parte de la memoria se comparte, muchos procesos pueden usarla, por lo que si suma todos los valores RSS, puede terminar fácilmente con más espacio del que tiene su sistema.

La memoria asignada también puede no estar en RSS hasta que el programa la use realmente. Entonces, si su programa asignó una gran cantidad de memoria por adelantado, luego la usa con el tiempo, podría ver que RSS sube y VSZ se mantiene igual.

También hay PSS (tamaño de conjunto proporcional). Esta es una medida más nueva que rastrea la memoria compartida como una proporción utilizada por el proceso actual. Entonces, si hubo dos procesos que usaban la misma biblioteca compartida de antes:

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

Todos los subprocesos comparten el mismo espacio de direcciones, por lo que RSS, VSZ y PSS para cada subproceso son idénticos a todos los otros subprocesos en el proceso. Use ps o top para ver esta información en linux / unix.

Hay mucho más que esto, para obtener más información, consulte las siguientes referencias:

Ver también:

jmh
fuente
17
Creo RSS hace incluir una memoria de las bibliotecas de enlace dinámico. Si se utilizan 3 procesos libxml2.so, la biblioteca compartida se contará en cada uno de sus RSS, por lo que la suma de sus RSS será mayor que la memoria real utilizada.
nfm
1
Eso es correcto. He arreglado mi respuesta, gracias por el aviso.
jmh
Estoy en ubuntu 16.04, y hay un proceso java que tiene 1.2G RES y 4.5G VIRT mostrando desde el topcomando. Este sistema no tiene ningún intercambio, swapon --showno devuelve nada. ¿Cómo explicas esto? Si vsz es intercambio + bibliotecas compartidas, en este caso, ¿las bibliotecas compartidas tienen más de 3.3G? ¿Es posible? Realmente confundido ...
Aaron Wang
No estoy realmente seguro. Eche un vistazo a esta respuesta sobre el uso de la memoria virtual Java: stackoverflow.com/a/561450/622115 . Versión corta: VSZ puede incluir espacio de almacenamiento dinámico asignado y no utilizado, así como archivos asignados a memoria.
jmh
Excelente. Solo agrega algo. si usa malloc (100 KB), solo use 1 KB en realidad. El rss es 1K y vsz es 100K, incluso si no hay intercambio aquí.
keniee van
53

RSS es Tamaño de conjunto residente (memoria físicamente residente; actualmente está ocupando espacio en la memoria física de la máquina), y VSZ es Tamaño de memoria virtual (espacio de direcciones asignado: tiene direcciones asignadas en el mapa de memoria del proceso, pero no necesariamente hay ninguna memoria real detrás de todo ahora mismo).

Tenga en cuenta que en estos días de máquinas virtuales comunes, la memoria física desde el punto de vista de la máquina puede no ser realmente memoria física real.

coste y flete
fuente
¿Le importaría proporcionar más información de lo que significa la abreviatura?
Pithikos
10

Ejemplo ejecutable mínimo

Para que esto tenga sentido, debe comprender los conceptos básicos de la paginación: ¿cómo funciona la paginación x86? y en particular que el sistema operativo puede asignar memoria virtual a través de tablas de páginas / su contabilidad interna (memoria virtual VSZ) antes de que realmente tenga un almacenamiento de respaldo en RAM o disco (memoria residente RSS).

Ahora para observar esto en acción, creemos un programa que:

  • asigna más RAM que nuestra memoria física con mmap
  • escribe un byte en cada página para garantizar que cada una de esas páginas pase de la memoria solo virtual (VSZ) a la memoria realmente utilizada (RSS)
  • comprueba el uso de memoria del proceso con uno de los métodos mencionados en: Uso de memoria del proceso actual en C

C Principal

#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;

/* /programming/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:
         * /programming/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 aguas arriba .

Compilar y ejecutar:

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

dónde:

  • 0x1000000000 == 64GiB: 2x RAM física de mi computadora de 32GiB
  • 0x200000000 == 8GiB: imprime la memoria cada 8GiB, por lo que deberíamos obtener 4 impresiones antes del bloqueo a aproximadamente 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory: requerido para Linux para permitirnos hacer una llamada mmap más grande que la RAM física: memoria máxima que malloc puede asignar

Salida del programa:

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

Estado de salida:

137

que según la regla del número de señal 128+ significa que obtuvimos el número de señal 9, que man 7 signaldice SIGKILL , que es enviado por el asesino de memoria insuficiente de Linux .

Interpretación de salida:

  • La memoria virtual VSZ permanece constante en printf '0x%X\n' 0x40009A4 KiB ~= 64GiB(los psvalores están en KiB) después del mmap.
  • El "uso de memoria real" de RSS aumenta perezosamente solo cuando tocamos las páginas. Por ejemplo:
    • en la primera impresión, tenemos extra_memory_committed 0, lo que significa que todavía no hemos tocado ninguna página. RSS es un pequeño 1648 KiBque se ha asignado para el inicio normal del programa, como área de texto, globales, etc.
    • En la segunda impresión, hemos escrito 8388608 KiB == 8GiBpáginas por valor. Como resultado, RSS aumentó exactamente 8GIB a8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS continúa aumentando en incrementos de 8GiB. La última impresión muestra aproximadamente 24 GiB de memoria, y antes de que se pudieran imprimir 32 GiB, el asesino de OOM mató el proceso

Ver también: /unix/35129/need-explanation-on-resident-set-size-virtual-size

OOM troncos asesinos

Nuestros dmesgcomandos han mostrado los registros asesinos de OOM.

Se ha pedido una interpretación exacta de estos en:

La primera línea del registro fue:

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

Así que vemos que, curiosamente, fue el demonio MongoDB que siempre se ejecuta en mi computadora portátil en segundo plano lo que activó por primera vez al asesino OOM, presumiblemente cuando el pobre estaba tratando de asignar algo de memoria.

Sin embargo, el asesino de OOM no necesariamente mata al que lo despertó.

Después de la invocación, el núcleo imprime una tabla o procesos que incluyen 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

y más adelante vemos que nuestro propio pequeño main.outfue asesinado en la invocación previa:

[ 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

Este registro menciona lo score 865que ese proceso tuvo, presumiblemente el puntaje asesino OOM más alto (peor) como se menciona en: /unix/153585/how-does-the-oom-killer-decide-which- proceso para matar primero

También es interesante que aparentemente todo sucedió tan rápido que antes de que se contara la memoria liberada, el proceso oomdespertó nuevamente DeadlineMonitor:

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

y esta vez que mató algunos procesos de Chromium, que generalmente es la memoria normal de mi computadora:

[ 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

Probado en Ubuntu 19.04, kernel de Linux 5.0.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
8

Creo que ya se ha dicho mucho sobre RSS vs VSZ. Desde la perspectiva del administrador / programador / usuario, cuando diseño / codifico aplicaciones, me preocupa más la RSZ, (memoria residente), ya que cada vez que extrae más y más variables (colmadas) verá que este valor se dispara. Pruebe un programa simple para construir una asignación de espacio basada en malloc en bucle y asegúrese de completar los datos en ese espacio malloc'd. RSS sigue subiendo. En lo que respecta a VSZ, es más un mapeo de memoria virtual que Linux, y una de sus características principales derivadas de los conceptos convencionales del sistema operativo. La gestión de VSZ se realiza mediante la gestión de memoria virtual del núcleo. Para obtener más información sobre VSZ, consulte la descripción de Robert Love en mm_struct y vm_struct, que forman parte de la estructura de datos básica de task_struct en el núcleo.

Anugraha Sinha
fuente
¿Te refieres al libro "Linux Kernel Development" de Love?
benjimin
1

No se gestionan, sino que se miden y posiblemente son limitadas (consulte la getrlimitllamada al sistema, también en getrlimit (2) ).

RSS significa tamaño de conjunto residente (la parte de su espacio de direcciones virtuales en RAM).

Puede consultar el espacio de direcciones virtuales del proceso 1234 usando proc (5) con cat /proc/1234/mapsy su estado (incluido el consumo de memoria) a través decat /proc/1234/status

Basile Starynkevitch
fuente
1
Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. - De la opinión
Maak
Proporcioné un segundo enlace. Uno de ellos seguirá siendo válido
Basile Starynkevitch