É assim que a paginação do linux deve se comportar? (porque parece horrível ...)

16

Quando meu sistema linux chega perto da paginação (isto é, no meu caso, 16GB de ram quase cheio, 16GB de swap completamente vazio) se um novo processo X tentar alocar alguma memória o sistema bloqueia completamente. Isto é, até que uma quantidade desproporcional de páginas, (com o tamanho total e taxa de pedidos de alocação de memória do X) tenha sido trocada. Observe que não apenas o gui se torna completamente não responsivo, mas até mesmo serviços básicos como o sshd são completamente bloqueados.

Estes são dois pedaços de código (reconhecidamente grosseiros) que eu uso para acionar esse comportamento de uma maneira mais "científica". O primeiro recebe dois números x, y da linha de comando e prossegue para aloque e inicialize vários fragmentos de y bytes até que mais de x bytes tenham sido alocados. E então apenas dorme indefinidamente. Isso será usado para colocar o sistema à beira da paginação.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char** argv) {
   long int max = -1;
   int mb = 0;
   long int size = 0;
   long int total = 0;
   char* buffer;

   if(argc > 1)
     {
       max = atol(argv[1]);
       size = atol(argv[2]);
     }
   printf("Max: %lu bytes\n", max);
   while((buffer=malloc(size)) != NULL && total < max) {
       memset(buffer, 0, size);
       mb++;
       total=mb*size;
       printf("Allocated %lu bytes\n", total);       
   }      
   sleep(3000000);
   return 0;
}

O segundo trecho de código faz exatamente o que o primeiro faz, exceto que ele tem um sleep(1); logo após o printf (não vou repetir o código inteiro). Este será usado quando o sistema estiver à beira da paginação para conseguir trocar as páginas de uma maneira "gentil", isto é, solicitando lentamente a alocação de novos pedaços de memória (para que o sistema certamente possa trocar páginas e acompanhar as novas solicitações).

Então, com os dois pedaços de código compilados, vamos chamar os respectivos exes fasteater e sloweater, vamos fazer isto:

1) inicie o seu gui favorito (não é estritamente necessário, claro)

2) inicie algum medidor mem / swap (por exemplo, watch -n 1 free )

3) inicie várias instâncias de fasteater x y em que x é da ordem de gigabytes e y é da ordem de megabytes. Faça isso até você quase encher o carneiro.

4) inicie uma instância de sloweater x y , novamente onde x é da ordem dos gigabytes e y é da ordem dos megabytes.

Após o passo 4, o que deve acontecer (e sempre acontece para o meu sistema) é que, logo após ter esgotado o aríete, o sistema irá travar completamente. gui está bloqueado sshd está bloqueado etc. MAS, não para sempre! Depois que o sloweater terminar seus pedidos de alocação, o sistema voltará à vida (após minutos de bloqueio, não segundos ...) com esta situação:

a) ram é sobre o tamanho

b) swap também está cheio (lembre-se, estava vazio no começo)

c) nenhuma intervenção matadora de oom.

E observe que a partição de troca está em um SSD. Assim, o sistema parece ser incapaz de mover páginas de ram para a troca (presumivelmente dos fasteaters que estão apenas dormindo) para abrir espaço para as solicitações lentas (e de apenas alguns megabytes) do sloweater.

Agora, alguém me corrija se eu estiver errado, mas isso não parece ser o modo como um sistema moderno deve se comportar nesse cenário. Parece se comportar como os sistemas antigos (waaaaay back) quando não havia suporte para paginação e o sistema de memória virtual simplesmente trocava todo o espaço de memória de algum processo em vez de poucas páginas.

Alguém pode testar isso também? E talvez alguém que também tenha um sistema BSD.

UPDATE 1 Segui o conselho de Mark Plotnick abaixo nos comentários e comecei vmstat 1 >out antes de continuar com a paginação teste. Você pode ver o resultado abaixo (eu cortei toda a parte inicial onde o ram é preenchido sem o envolvimento de swap):

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
0  0   6144 160792      8 272868    0    0     0     0  281 1839  1  0 99  0  0
0  0   6144 177844      8 246096    0    0     0     0  425 2300  1  1 99  0  0
0  0   6144 168528      8 246112    0    0    16     0  293 1939  1  0 99  0  0
0  0   6144 158320      8 246116    0    0     0     0  261 1245  0  0 100  0  0
2  0  10752 161624      8 229024    0 4820 17148  4820  845 3656  1  2 97  0  0
2  0  10752 157300      8 228096    0    0 88348     0 2114 8902  0  5 94  1  0
0  0  10752 176108      8 200052    0    0 108312     0 2466 9772  1  5 91  3  0
0  0  10752 170040      8 196780    0    0 17380     0  507 1895  0  1 99  0  0
0 10  10752 160436      8 191244    0    0 346872    20 4184 17274  1  9 64 26  0
0 29 12033856 152888      8 116696 5992 15916880 1074132 15925816 819374 2473643  0 94  0  6  0
3 21 12031552 295644      8 136536 1188    0 11348     0 1362 3913  0  1 10 89  0
0 11 12030528 394072      8 151000 2016    0 17304     0  907 2867  0  1 13 86  0
0 11 12030016 485252      8 158528  708    0  7472     0  566 1680  0  1 23 77  0
0 11 12029248 605820      8 159608  900    0  2024     0  371 1289  0  0 31 69  0
0 11 12028992 725344      8 160472 1076    0  1204     0  387 1381  0  1 33 66  0
0 12 12028480 842276      8 162056  724    0  3112     0  357 1142  0  1 38 61  0
0 13 12027968 937828      8 162652  776    0  1312     0  363 1191  0  1 31 68  0
0  9 12027456 1085672      8 163260  656    0  1520     0  439 1497  0  0 30 69  0
0 10 12027200 1207624      8 163684  728    0   992     0  411 1268  0  0 42 58  0
0  9 12026688 1331492      8 164740  600    0  1732     0  392 1203  0  0 36 64  0
0  9 12026432 1458312      8 166020  628    0  1644     0  366 1176  0  0 33 66  0

Como você pode ver, assim que a troca se envolve, há uma troca maciça de 15916880 Kbytes de uma só vez, o que, eu acho, dura toda a duração do congelamento do sistema. E tudo isso é aparentemente causado por um processo (o sloweater) que apenas pede 10MB por segundo.

UPDATE 2: Eu fiz uma instalação rápida do freebsd e repeti o mesmo esquema de alocação usado com o linux ... e foi tão bom quanto deveria ser. O freebsd trocava páginas gradualmente enquanto o sloweater distribuía todos os seus 10 MB de memória. Não é um engate de qualquer tipo ... WTF está acontecendo aqui ?!

UPDATE 3: Arquivei um bug com o bugtracker do kernel. Parece estar recebendo alguma atenção, então ... dedos cruzados ...

    
por John Terragon 03.05.2018 / 18:08

1 resposta

-2

Você está apenas alocando memória - você não coloca nada nela. Um programa "normal" alocaria um pedaço e começaria a usá-lo. A alocação não é o mesmo que o uso de memória.

    
por 23.05.2018 / 15:43