¿Cómo puede disminuir la memoria física libre mientras la memoria 'Res' utilizada por los procesos es constante?

¿Cómo puede disminuir la memoria física libre mientras la memoria 'Res' utilizada por los procesos es constante?

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/ freeinforma como memoria física libre. Lo que muestran los gráficos inferiores es exactamente lo que topinforma la columna 'Res'. Tenga en cuenta que el área marcada Rubyes 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 topy freeson 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?

información relacionada