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 y
donde 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 >out
antes 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 ...
fuente
vmstat 1>somefile
directamente desde el sistema y luego ver qué informa después de que el sistema haya vuelto a la vida. Lo intentaréswappiness
es el valor predeterminado 60 (no es que cambiarlo dé un mejor resultado). El núcleo utilizado con lavmstat
ejecució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.Respuestas:
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.
fuente
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.
fuente