
Observo el siguiente comportamiento que no puedo explicar: la cantidad de memoria física libre reportada por un servidor aumenta, mientras que la memoria 'Res' reportada por los procesos que consumen más memoria (procesos del servidor web) es casi plana.
Lo que principalmente quiero entender es: cómo es posible que el uso de la memoria física aumente mientras la memoria residente informada por los procesos es constante. ¿Qué podría estar sucediendo dentro de estos procesos para causar ese comportamiento observable, especialmente sin producir mucha carga?
En otras palabras: ¿qué puede suceder dentro de un proceso como esa "memoria" que primero se informó como "residente", pero que en realidad no ocupaba ninguna memoria física, cambia de tal manera que todavía se informa como "residente", pero ahora ¿También ocupa realmente memoria física?
Ejemplo: tengo un servidor virtual con 2GB de memoria. Ayer a las 12:00, alrededor de 800 MB (40%) estaban en uso, según informó top
/ free
[1]. La mayor parte es utilizada por unos pocos procesos, que en conjunto reportaron alrededor de 1,2 GB de memoria residente utilizada[2].
Luego comencé algunas pruebas (realizando grandes cantidades de solicitudes HTTP atendidas por estos procesos), que aumentaron el uso de la memoria física a 1,2 GB (60 %) y aumentaron la memoria residente utilizada por los procesos a 3,2 GB. Después de eso, no toqué el servidor en absoluto y no está disponible públicamente: la carga fue <0,03 después.
Sin embargo, si bien la memoria residente informada por los procesos se mantuvo estable en 3,2 GB, el uso de la memoria física aumentó lentamente y en algún momento superó el 90 % (1,8 GB), lo que provocó que se levantaran banderas. Dentro de estos procesos del servidor web, no estaba sucediendo nada en ese momento (como lo demuestra la carga) y no hay ningún trabajo especial en ejecución.
Se puede ver un gráfico del escenario anterior.aquí. Lo que muestra el gráfico superior es exactamente lo que top
/ free
informa como memoria física libre. Lo que muestran los gráficos inferiores es exactamente lo que top
informa la columna 'Res'. Tenga en cuenta que el área marcada Ruby
es el total de 6 procesos.
[1] Normalmente, en estos servidores, toda la memoria se marca como "Usada" y toda la memoria libre se utiliza para cachés. Con todo quiero decir: hasta el último byte. Todos los demás números en top
y free
son 0.
[2] Entiendo que la suma de la memoria residente reportada por varios procesos puede exceder la memoria física utilizada, pero no creo saberlo.todode las formas en que esto puede suceder.
Respuesta1
Esto sucede porque RSS esnoun valor autorizado que le indica cuánta memoria utiliza ese programa. Es un valor autorizado en cuanto a cuánta memoria residente asigna ese programa. Y hay una diferencia.
En el mejor de los casos, RSS sólo se puede utilizar como una pista de cuánta memoria está utilizando.
El kernel tiene muchos trucos bajo la manga para ahorrar memoria. Los procesos pueden compartir mucha memoria, especialmente los procesos que se bifurcan.
Si tiene un padre que asigna 100 M de memoria, luego genera un hijo, ambos procesos compartirán esa área de memoria, tanto el padre como el hijo afirmarán tener un valor RSS de >= 100 M, porque ambos se asignan al misma región de la memoria. Técnicamente esto es correcto, el RSS para el proceso principal es >= 100M ya que esa es la cantidad de memoria que ha asignado el proceso.yel proceso hijo también tiene RSS >= 100M porque ese procesotambiéntiene tanto mapeado, simplemente resulta que ambos procesos comparten (en su mayoría) las mismas asignaciones.
Puedes demostrar esto con algo de Python simple.
#!/usr/bin/python
import os,sys,signal
HOG = 'A' * 104857600 ## 100 MB
try:
for i in range(100):
pid = os.fork()
if pid:
continue
else:
break
signal.pause()
except KeyboardInterrupt:
sys.exit(0)
Este programa crea un área de memoria de 100 M y la llena con 'A's. Luego genera 100 hijos (101 procesos en total) y luego espera Ctrl-c.
Este es el escenario anterior.
$ top -bn1 -u matthew
top - 21:03:04 up 11 min, 1 user, load average: 0.04, 0.08, 0.09
Tasks: 212 total, 1 running, 211 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.7 us, 0.3 sy, 0.0 ni, 98.7 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 16124248 total, 1513728 used, 14610520 free, 78268 buffers
KiB Swap: 8069116 total, 0 used, 8069116 free, 578148 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1837 matthew 20 0 767916 5072 3400 S 0.0 0.0 0:00.06 gnome-keyr+
1880 matthew 20 0 13920 608 468 S 0.0 0.0 0:00.00 dbus-launch
1949 matthew 20 0 307180 2804 2312 S 0.0 0.0 0:00.01 gvfsd
2051 matthew 20 0 337684 2908 2436 S 0.0 0.0 0:00.00 at-spi-bus+
2059 matthew 20 0 127260 2920 2360 S 0.0 0.0 0:00.05 at-spi2-re+
2082 matthew 9 -11 486316 7044 4376 S 0.0 0.0 0:00.09 pulseaudio
2121 matthew 20 0 317660 2952 2324 S 0.0 0.0 0:00.00 gvfs-gphot+
2132 matthew 20 0 1440732 105732 30156 S 0.0 0.7 0:09.64 gnome-shell
2145 matthew 20 0 513076 3996 3064 S 0.0 0.0 0:00.00 gsd-printer
2160 matthew 20 0 313300 3488 2940 S 0.0 0.0 0:00.00 ibus-dconf
2172 matthew 20 0 775428 14000 10348 S 0.0 0.1 0:00.05 gnome-shel+
2182 matthew 20 0 319120 7120 5444 S 0.0 0.0 0:00.07 mission-co+
2196 matthew 20 0 232848 2708 2164 S 0.0 0.0 0:00.00 gvfsd-meta+
2206 matthew 20 0 408000 11828 8084 S 0.0 0.1 0:00.06 abrt-applet
2209 matthew 20 0 761072 15120 10680 S 0.0 0.1 0:00.13 nm-applet
2216 matthew 20 0 873088 14956 10600 S 0.0 0.1 0:00.09 evolution-+
2224 matthew 20 0 1357640 29248 14052 S 0.0 0.2 0:00.26 evolution-+
2403 matthew 20 0 295036 6680 3876 S 0.0 0.0 0:00.01 telepathy-+
2475 matthew 20 0 380916 2756 2264 S 0.0 0.0 0:00.00 gvfsd-burn
2486 matthew 20 0 8460 736 608 S 0.0 0.0 0:00.00 gnome-pty-+
2617 matthew 20 0 116412 3068 1596 S 0.0 0.0 0:00.04 bash
2888 matthew 20 0 457196 9868 5164 S 0.0 0.1 0:00.05 telepathy-+
3347 matthew 20 0 123648 1400 1020 R 0.0 0.0 0:00.00 top
La parte superior muestra 14610520 KB de memoria libre.
Ejecutemos nuestro programa:
$ python trick_rss.py & top -bn1 -u matthew
[2] 3465
top - 21:04:54 up 13 min, 1 user, load average: 0.05, 0.07, 0.08
Tasks: 415 total, 1 running, 414 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.7 us, 0.3 sy, 0.0 ni, 98.8 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 16124248 total, 1832040 used, 14292208 free, 78320 buffers
KiB Swap: 8069116 total, 0 used, 8069116 free, 578144 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3465 matthew 20 0 227652 106676 1792 S 31.7 0.7 0:00.05 python
2483 matthew 20 0 641568 18736 11656 S 6.3 0.1 0:01.26 gnome-term+
1837 matthew 20 0 767916 5072 3400 S 0.0 0.0 0:00.06 gnome-keyr+
1880 matthew 20 0 13920 608 468 S 0.0 0.0 0:00.00 dbus-launch
1949 matthew 20 0 307180 2804 2312 S 0.0 0.0 0:00.01 gvfsd
2051 matthew 20 0 337684 2908 2436 S 0.0 0.0 0:00.00 at-spi-bus+
2059 matthew 20 0 127260 2920 2360 S 0.0 0.0 0:00.05 at-spi2-re+
2082 matthew 9 -11 486316 7044 4376 S 0.0 0.0 0:00.09 pulseaudio
2121 matthew 20 0 317660 2952 2324 S 0.0 0.0 0:00.00 gvfs-gphot+
2136 matthew 20 0 178692 2588 1788 S 0.0 0.0 0:00.00 dconf-serv+
2145 matthew 20 0 513076 3996 3064 S 0.0 0.0 0:00.00 gsd-printer
2160 matthew 20 0 313300 3488 2940 S 0.0 0.0 0:00.00 ibus-dconf
2172 matthew 20 0 775428 14000 10348 S 0.0 0.1 0:00.05 gnome-shel+
2182 matthew 20 0 319120 7120 5444 S 0.0 0.0 0:00.07 mission-co+
2196 matthew 20 0 232848 2708 2164 S 0.0 0.0 0:00.00 gvfsd-meta+
2206 matthew 20 0 408000 11828 8084 S 0.0 0.1 0:00.06 abrt-applet
2209 matthew 20 0 761072 15120 10680 S 0.0 0.1 0:00.14 nm-applet
2216 matthew 20 0 873088 14956 10600 S 0.0 0.1 0:00.10 evolution-+
2224 matthew 20 0 1357640 29248 14052 S 0.0 0.2 0:00.26 evolution-+
2403 matthew 20 0 295036 6680 3876 S 0.0 0.0 0:00.01 telepathy-+
2475 matthew 20 0 380916 2756 2264 S 0.0 0.0 0:00.00 gvfsd-burn
2487 matthew 20 0 116544 3316 1716 S 0.0 0.0 0:00.09 bash
2804 matthew 20 0 1239196 275576 41432 S 0.0 1.7 0:25.54 firefox
2890 matthew 20 0 436688 15932 7288 S 0.0 0.1 0:00.05 telepathy-+
3360 matthew 20 0 227652 106680 1792 S 0.0 0.7 0:00.05 python
3366 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3368 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3370 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3372 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3374 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3376 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3378 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3380 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3382 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3384 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3386 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3388 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3390 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3392 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3394 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3396 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3398 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3400 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3402 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3404 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3406 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3408 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3410 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3412 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3414 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3416 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3418 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3420 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3422 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3424 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3426 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3428 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3430 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3432 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3434 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3436 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3438 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3440 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3442 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3444 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3446 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3448 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3450 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3452 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3454 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3456 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3458 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3460 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3462 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3464 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3467 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3469 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3471 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3473 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3475 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3477 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3479 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3481 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3483 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3485 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3487 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3489 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3491 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3493 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3495 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3497 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3499 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3501 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3503 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3505 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3507 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3509 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3511 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3513 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3515 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3517 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3519 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3521 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3523 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3525 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3527 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3529 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3531 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3533 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3535 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3537 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3539 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3541 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3543 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3545 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3547 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3549 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3551 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3553 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3555 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3557 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3559 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3561 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3563 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3565 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
Tengo 14292208 Kb libres. Se han agotado unos 300 M de memoria. Pero, si sigo lo que me dice RSS, ¡en realidad he usado 10 GB de memoria!
Finalmente, si observa las asignaciones de procesos, puede ver que las direcciones de la memoria virtual son las mismas entre sí.
$ pmap -x 3561
...
00007f05da5e8000 102404 102404 102404 rw--- [ anon ]
...
$ pmap -x 3565
...
00007f05da5e8000 102404 102404 102404 rw--- [ anon ]
...
Copia perezosa
Este programa en C demuestra que se produce una copia diferida; en este escenario, todos los procesos se asignan a la misma región de la memoria, pero los hijos han sobrescrito el contenido. En segundo plano, el kernel ha reasignado estas páginas a diferentes ubicaciones en la memoria real, pero muestra el mismo espacio de direcciones virtuales.
Ahora, cada instancia ocupa memoria pero el valor RSS permanece constante.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
int main() {
int i;
char c=65;
pid_t pid;
signal(SIGCHLD, SIG_IGN);
/* Allocate some memory */
char *hog = malloc(104857600);
memset(hog, c, 104857600);
for (i=1; i < 4; i++) {
if (fork())
continue;
memset(hog, c+i, 104857600);
break;
}
sleep(3);
printf("Pid %d shows HOG[1048576] saying %c\n", getpid(), hog[1048576]);
pause();
}
Compilar con gcc -o trick_rss trick_rss.c
. Y corre con free -m; ./trick_rss & sleep 5; free -m
.
Obtienes el siguiente resultado;
$ free -m; ./trick_rss & sleep 5; free -m
total used free shared buffers cached
Mem: 15746 2477 13268 0 79 589
-/+ buffers/cache: 1808 13938
Swap: 7879 0 7879
[3] 4422
Pid 4422 shows HOG[1048576] saying A
Pid 4424 shows HOG[1048576] saying B
Pid 4425 shows HOG[1048576] saying C
Pid 4426 shows HOG[1048576] saying D
total used free shared buffers cached
Mem: 15746 2878 12867 0 79 589
-/+ buffers/cache: 2209 13536
Swap: 7879 0 7879
Respuesta2
La cantidad de memoria física utilizada podría crecer a medida que disminuye la cantidad de memoria compartida entre los procesos Ruby (u otros). Sin embargo, en su caso, el sistema está inactivo, por lo que no esperaría ningún cambio. Posiblemente el recolector de basura Ruby esté provocando que el intercambio disminuya, ya que esta cita dehttp://www.rubyenterpriseedition.com/faq.htmlesta diciendo:
Por lo tanto, un ciclo de recolección de basura dará como resultado que se escriban en todos los objetos (o en la jerga de los sistemas operativos: las páginas de memoria de los objetos se ensucian). El sistema operativo copiará toda esa memoria, anulando así el efecto de copia en escritura.
¿Cómo es la cantidad de memoria compartida durante este período de tiempo?