Respuestas:
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:
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.
top
comando. Este sistema no tiene ningún intercambio, swapon --show
no 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 ...
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.
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:
mmap
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;
}
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:
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 asignarSalida 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 SIGKILL , que es enviado por el asesino de memoria insuficiente de Linux .
Interpretación de salida:
printf '0x%X\n' 0x40009A4 KiB ~= 64GiB
(los ps
valores están en KiB) después del mmap.extra_memory_committed 0
, lo que significa que todavía 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.8388608 KiB == 8GiB
páginas por valor. Como resultado, RSS aumentó exactamente 8GIB a8390256 KiB == 8388608 KiB + 1648 KiB
Ver también: /unix/35129/need-explanation-on-resident-set-size-virtual-size
OOM troncos asesinos
Nuestros dmesg
comandos 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.out
fue 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 865
que 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 oom
despertó 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.
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.
No se gestionan, sino que se miden y posiblemente son limitadas (consulte la getrlimit
llamada 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/maps
y su estado (incluido el consumo de memoria) a través decat /proc/1234/status