Como a memória física livre pode diminuir enquanto a memória 'Res' usada pelos processos é constante?

3

Observo o seguinte comportamento que não consigo explicar: a quantidade de memória física livre relatada por um servidor aumenta, enquanto a memória 'Res' relatada pelos processos que mais consomem muita memória (processos do servidor da web) é quase plana.

O que eu quero principalmente entender é: como é possível que o uso da memória física aumente enquanto a memória residente relatada pelos processos é constante. O que poderia estar acontecendo dentro desses processos para causar esse comportamento observável, especialmente sem produzir muita carga?

Em outras palavras: o que pode acontecer dentro de um processo de tal forma que a 'memória' foi primeiro relatada como 'residente', mas na verdade não ocupou nenhuma alteração de memória física de tal forma que ainda seja reportada como 'residente' , mas agora também ocupa a memória física?

Exemplo: Eu tenho um servidor virtual com 2 GB de memória. Ontem às 12:00, cerca de 800MB (40%) estavam em uso, conforme relatado por top / free [1]. A maioria é usada por alguns processos, que juntos relataram cerca de 1,2 GB de memória residente usada [2].

Eu, então, iniciei alguns testes (executando grandes quantidades de solicitações HTTP atendidas por esses processos), que aumentaram o uso de memória física para 1,2 GB (60%) e aumentaram a memória residente usada pelos processos para 3,2 GB. Depois disso, eu não toquei no servidor e ele não está disponível publicamente: a carga era < 0,03 depois.

No entanto, enquanto a memória residente relatada pelos processos era plana em 3,2 GB, o uso de memória física aumentou lentamente e em algum momento ultrapassou 90% (1,8 GB), fazendo com que as bandeiras fossem levantadas. Dentro desses processos do servidor da Web, nada estava acontecendo naquele momento (conforme evidenciado pela carga) e não há trabalhos especiais em execução.

Um gráfico do cenário acima pode ser visto aqui . O que o gráfico superior mostra é exatamente o que top / free relata como a memória física livre. O que os gráficos mais abaixo mostram é exatamente o que top reporta na coluna 'Res'. Observe que a área marcada com Ruby é o total de 6 processos.

[1] Normalmente, nesses servidores, toda a memória é marcada como 'Usada' e toda a memória livre é usada para caches. Por tudo o que quero dizer: até o último byte. Todos os outros números em top e free são 0.

[2] Eu entendo que a soma de memória residente relatada por vários processos pode exceder a memória física usada, mas eu não acho que conheço todas as maneiras em que isso pode acontecer.

    
por Confusion 05.12.2013 / 12:15

2 respostas

4

Isso acontece porque o RSS não é um valor autoritativo que informa quanto dessa memória está sendo usada pelo programa. É um valor autoritário de quanto memória residente é mapeada por esse programa. E há uma diferença.

O RSS pode, na melhor das hipóteses, ser usado apenas como uma dica para a quantidade de memória que você está utilizando.

O kernel tem muitos truques na manga para economizar memória. Os processos podem compartilhar muita memória, especialmente os processos que se baseiam.

Se você tiver um pai que aloca 100 M de memória e depois gerar um filho desses dois processos compartilharão essa área de memória, tanto o pai quanto o filho afirmarão ter um valor de RSS de > = 100M, porque ambos mapeiam para a mesma região de memória. Tecnicamente, isso está correto, o RSS para o processo pai é > = 100M, já que a quantidade de memória mapeada pelo processo, e o processo filho também tem RSS > = 100M porque esse processo também tem muito mapeado, acontece que ambos os processos compartilham (principalmente) os mesmos mapeamentos.

Você pode demonstrar isso com um simples python.

#!/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 cria uma área de memória de 100M e preenche os 'A's. Em seguida, ele gera 100 filhos (101 processos totais) e aguarda por um ctrl-c.

Este é o cenário 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

Top mostra 14610520 KB de memória livre.

Vamos executar nosso 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

Eu tenho 14292208 Kb grátis. Cerca de 300 milhões de memória foram consumidos. Mas, se eu passar o que o RSS está me dizendo, eu usei 10GB de memória!

Por fim, se você der uma olhada nos mapeamentos de processo, poderá ver que os endereços de memória virtual são os mesmos um do outro.

$ pmap -x 3561
...
00007f05da5e8000  102404  102404  102404 rw---   [ anon ]
...

$ pmap -x 3565
...
00007f05da5e8000  102404  102404  102404 rw---   [ anon ]
...

Copiando preguiçoso

Este programa C demonstra a ocorrência de cópias ociosas; neste cenário, todos os processos mapeiam para a mesma região de memória, mas as crianças sobrescreveram o conteúdo. No segundo plano, o kernel remapea essas páginas para locais diferentes na memória real, mas mostra o mesmo espaço de endereço virtual.

Agora, cada instância realmente ocupa memória, mas o valor de 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();
}

Compile com gcc -o trick_rss trick_rss.c . E corra com free -m; ./trick_rss & sleep 5; free -m .

Você obtém o seguinte 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
    
por 05.12.2013 / 22:08
1

A quantidade de memória física usada pode aumentar à medida que a quantidade de memória compartilhada entre os processos ruby (ou outros) diminui. No seu caso, no entanto, o sistema está ocioso para que você não espere nenhuma alteração. Possivelmente, o coletor de lixo ruby está fazendo com que o compartilhamento diminua, pois essa citação do link está dizendo:

A garbage collection cycle will thus result in all objects being written to (or in operating systems jargon: the memory pages of the objects are made dirty). The OS will copy all that memory, thus negating the effect of copy-on-write.

Como é a quantidade de memória compartilhada nesse período?

    
por 05.12.2013 / 21:30

Tags