¿Es así como debería comportarse la paginación de Linux?


26

Cuando mi sistema Linux se acerca a la paginación (es decir, en mi caso, 16 GB de memoria RAM casi llena, intercambio de 16 GB completamente vacío) si un nuevo proceso X intenta asignar algo de memoria que el sistema bloquea por completo. Es decir, hasta que se haya intercambiado una cantidad desproporcionada de páginas (wrt, el tamaño total y la velocidad de las solicitudes de asignación de memoria de X). Tenga en cuenta que no solo la interfaz gráfica de usuario deja de responder por completo, sino que incluso los servicios básicos como sshd están completamente bloqueados.

Estas son dos piezas de código (ciertamente crudo) que utilizo para desencadenar este comportamiento de una manera más "científica". El primero obtiene dos números x, y de la línea de comando y procede a asignar e inicializar múltiples fragmentos de bytes y hasta que se hayan asignado más de x bytes totales. Y luego solo duerme indefinidamente. Esto se utilizará para poner el sistema al borde de la paginación.

#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;
}

El segundo fragmento de código hace exactamente lo que hace el primero, excepto que tiene un sleep(1);derecho después del printf(no voy a repetir todo el código). Este se usará cuando el sistema esté al borde de la paginación para que pueda intercambiar páginas de una manera "suave", es decir, solicitando lentamente la asignación de nuevos fragmentos de memoria (de modo que el sistema ciertamente pueda intercambiar páginas) y mantenerse al día con las nuevas solicitudes).

Entonces, con las dos piezas de código compiladas, llamemos a los respectivos ex fasteater y sloweater, hagamos esto:

1) inicie su interfaz gráfica de usuario favorita (no estrictamente necesario, por supuesto)

2) iniciar un medidor mem / swap (por ejemplo watch -n 1 free)

3) iniciar múltiples instancias de fasteater x ydonde x es del orden de gigabytes e y es del orden de megabytes. Hazlo hasta que casi llenes el carnero.

4) iniciar una instancia de sloweater x y, nuevamente donde x es del orden de gigabytes e y es del orden de megabytes.

Después del paso 4) lo que debería suceder (y siempre sucede para mi sistema) es que justo después de haber agotado el ram, el sistema se bloqueará por completo. gui está bloqueado sshd está bloqueado, etc. ¡PERO, no para siempre! Después de que sloweater haya finalizado sus solicitudes de asignación, el sistema volverá a la vida (después de minutos de bloqueo, no segundos ...) con esta situación:

a) el carnero está casi lleno

b) el intercambio también está lleno (recuerde, estaba vacío al principio)

c) ninguna intervención asesina oom.

Y observe que la partición de intercambio está en un SSD. Entonces, el sistema parece ser incapaz de mover gradualmente las páginas del carnero al intercambio (presumiblemente de los fasteaters que están durmiendo) para hacer espacio para las solicitudes lentas (y de solo unos pocos megabytes) del comedor lento.

Ahora, alguien me corrige si me equivoco, pero esta no parece la forma en que un sistema moderno debería comportarse en esta configuración. Parece que se comporta como los sistemas antiguos (muuuucho atrás) cuando no había soporte para paginación y el sistema de memoria virtual simplemente intercambiaba todo el espacio de memoria de algún proceso en lugar de pocas páginas.

¿Alguien puede probar esto también? Y tal vez alguien que también tenga un sistema BSD.

ACTUALIZACIÓN 1 Seguí los consejos de Mark Plotnick a continuación en los comentarios y comencé vmstat 1 >outantes de continuar con la prueba de paginación. Puede ver el resultado a continuación (corté toda la parte inicial donde se llena el ariete sin participación de intercambio):

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 puede ver, tan pronto como el intercambio se involucra, hay un intercambio masivo de 15916880 Kbytes a la vez, lo que, supongo, dura toda la duración de la congelación del sistema. Y todo esto aparentemente es causado por un proceso (el sloweater) que solo pide 10 MB por segundo.

ACTUALIZACIÓN 2: Hice una instalación rápida de FreeBSD y repetí el mismo esquema de asignación utilizado con Linux ... y fue tan sencillo como debería ser. FreeBSD cambió las páginas gradualmente mientras que el comedor lento asignaba todos sus fragmentos de memoria de 10 MB. Ningún problema de ningún tipo ... ¡¿Qué está pasando aquí ?!

ACTUALIZACIÓN 3: archivé un error con el rastreador de errores del kernel. Parece estar recibiendo atención, así que ... dedos cruzados ...


2
Como mencioné, todo está bloqueado. Intenté enviar algo desde otro sistema, solo se agota el tiempo de espera.
John Terragon

2
Si inicio vmstat 1 con salida estándar, creo que se congelará. Pero tienes razón, podría comenzar vmstat 1>somefiledirectamente desde el sistema y luego ver qué informa después de que el sistema haya vuelto a la vida. Lo intentaré
John Terragon

2
Usé vmstat. Resultados en la actualización anterior.
John Terragon

3
swappinesses el valor predeterminado 60 (no es que cambiarlo dé un mejor resultado). El núcleo utilizado con la vmstatejecución es 4.14.35, pero he probado 4.15, 4.16 e incluso he vuelto a la serie 4.0 (!): Siempre el mismo comportamiento. Y no es que esté usando una distribución extraña, es solo debian. No uso las imágenes del núcleo de debian (no es que las mías tengan configuraciones inusuales) pero he intentado uno de esos ... mismo comportamiento.
John Terragon

2
Muy interesante discusión sobre el error del kernel! Y parece que aisló este problema para intercambiar particiones cifradas con LUKS. Es posible que desee editar su respuesta o posiblemente publicar una respuesta usted mismo (con las soluciones conocidas hasta ahora, y tal vez seguir actualizándola a medida que la discusión de LKML llegue a resultados más concluyentes). ¡Realmente impresionante ver la comunidad del kernel de Linux en funcionamiento! 😁
filbranden

Respuestas:


1

Esto es exactamente para lo que existe protección contra golpes.

Supervisa constantemente el estado de intercambio y, cuando algo accidentalmente comienza a ocupar una gran cantidad de RAM, congela temporalmente los procesos codiciosos de RAM, por lo que el núcleo tiene tiempo para intercambiar algo de memoria sin hacer que todo el sistema no responda.


-3

Solo está asignando memoria, en realidad no pone nada en ella. Un programa "normal" asignaría un fragmento y luego comenzaría a usarlo. La asignación no es lo mismo que el uso de memoria.


3
Bienvenido a publicar en Unix StackExchange. Pone datos en él, esos datos simplemente son cero. Ver el memset (). El kernel de Linux proporciona una página física de RAM tan pronto como escribe en la página virtual; no mira el valor específico que se escribe.
sourcejedi

En realidad, compilé y ejecuté esto en mi escritorio comenzando con 2GB usados, 6GB gratis. En realidad, se cambió a un ritmo lento inicialmente y solo cuando alcanzó el límite se cambió agresivamente, lo que provocó que varias acciones de la GUI se agarroten.
Jeremy Boden
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.