GNU/Linux >> Tutoriales Linux >  >> Linux

Necesita explicación sobre el tamaño del conjunto residente/tamaño virtual

RSS es la cantidad de memoria que este proceso tiene actualmente en la memoria principal (RAM). VSZ es la cantidad de memoria virtual que tiene el proceso en total. Esto incluye todos los tipos de memoria, tanto en RAM como intercambiada. Estos números pueden distorsionarse porque también incluyen bibliotecas compartidas y otros tipos de memoria. Puede tener quinientas instancias de bash ejecutándose, y el tamaño total de su huella de memoria no será la suma de sus valores RSS o VSZ.

Si necesita obtener una idea más detallada sobre la huella de memoria de un proceso, tiene algunas opciones. Puedes pasar por /proc/$PID/map y elimina las cosas que no te gustan. Si se trata de bibliotecas compartidas, el cálculo podría volverse complejo dependiendo de sus necesidades (que creo recordar).

Si solo le importa el tamaño del montón del proceso, siempre puede analizar el [heap] entrada en el map expediente. El tamaño que el kernel ha asignado para el montón del proceso puede o no reflejar la cantidad exacta de bytes que el proceso pidió. para ser asignado. Hay detalles minuciosos, elementos internos del kernel y optimizaciones que pueden descartar esto. En un mundo ideal, será tanto como necesite su proceso, redondeado al múltiplo más cercano del tamaño de la página del sistema (getconf PAGESIZE le dirá cuál es:en las PC, probablemente sean 4096 bytes).

Si desea ver cuánta memoria ha asignado un proceso , una de las mejores formas es renunciar a las métricas del lado del kernel. En su lugar, instrumenta las funciones de asignación (des)asignación de memoria de montón de la biblioteca C con el LD_PRELOAD mecanismo. Personalmente, abuso ligeramente de valgrind para obtener información sobre este tipo de cosas. (Tenga en cuenta que la aplicación de la instrumentación requerirá reiniciar el proceso).

Tenga en cuenta que, dado que también puede realizar evaluaciones comparativas de los tiempos de ejecución, valgrind hará que sus programas sean un poco más lentos (pero probablemente dentro de sus tolerancias).


Ejemplo ejecutable mínimo

Para que esto tenga sentido, debe comprender los conceptos básicos de paginación:https://stackoverflow.com/questions/18431261/how-does-x86-paging-work y, en particular, que el sistema operativo puede asignar memoria virtual a través de tablas de página / su mantenimiento de libros de memoria 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 virtual únicamente (VSZ) a la memoria realmente utilizada (RSS)
  • comprueba el uso de memoria del proceso con uno de los métodos mencionados en:https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c

principal.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 ascendente.

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

donde:

  • 0x1000000000 ==64GiB:2 veces la 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 en alrededor de 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory :requerido para que Linux nos permita hacer una llamada mmap más grande que la memoria RAM física:https://stackoverflow.com/questions/2798330/maximum-memory-which-malloc-can-allocate/57687432#57687432

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 signal dice que es SIGKILL, que es enviado por Linux out-of-memory killer.

Interpretación de salida:

  • La memoria virtual de VSZ permanece constante en printf '0x%X\n' 0x40009A4 KiB ~= 64GiB (ps los valores 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 aún no hemos tocado ninguna página. RSS es un pequeño 1648 KiB que se ha asignado para el inicio normal del programa como área de texto, globales, etc.
    • en la segunda impresión, hemos escrito a 8388608 KiB == 8GiB valor de las páginas. Como resultado, RSS aumentó exactamente 8 GIB a 8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS continúa aumentando en incrementos de 8GiB. La última impresión muestra alrededor de 24 GiB de memoria, y antes de que se pudieran imprimir 32 GiB, el asesino OOM eliminó el proceso

Consulte también:Necesita explicación sobre el tamaño del conjunto residente/tamaño virtual

Registros asesinos de OOM

Nuestro dmesg los comandos han mostrado los registros asesinos de OOM.

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

  • https://stackoverflow.com/questions/9199731/understanding-the-linux-oom-killers-logs pero echemos un vistazo rápido aquí.
  • https://serverfault.com/questions/548736/how-to-read-oom-killer-syslog-messages

La primera línea del registro era:

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

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

Sin embargo, el asesino OOM no necesariamente mata a quien lo despertó.

Después de la invocación, el kernel imprime una tabla o procesos que incluyen el 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 pequeño main.out en realidad fue asesinado en la invocación anterior:

[ 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 el score 865 que ese proceso tuvo, presumiblemente, la puntuación más alta (peor) del asesino OOM como se menciona en:¿Cómo decide el asesino OOM qué proceso matar primero?

También es interesante que aparentemente todo sucedió tan rápido que antes de que se contabilizara la memoria liberada, el oom fue despertado nuevamente por el DeadlineMonitor proceso:

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

y esta vez eso eliminó algún proceso de Chromium, que generalmente es el acaparador de 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.


Linux
  1. Cómo verificar el tamaño de RAM en la línea de comandos de Linux en Gb

  2. Comandos de Linux:exploración de la memoria virtual con vmstat

  3. Aumente el tamaño del disco virtual de Windows10 VM en QEMU-KVM

  4. Linux:¿necesita una explicación sobre el tamaño del conjunto residente/tamaño virtual?

  5. Cambiar el tamaño de una ventana a un tamaño establecido en Linux

Swappiness en Linux:Todo lo que necesitas saber

Cómo extender el tamaño del disco de la máquina virtual KVM en Linux

Cómo configurar servidores virtuales Apache en Ubuntu 18.04

Cómo configurar servidores virtuales Apache en Ubuntu 20.04

Gestión de memoria de Linux:memoria virtual y paginación de demanda

Encuentra el tamaño de RAM en Linux