La Sección 9.6 "Sobrecompromiso y OOM" en el documento que @dunxd menciona es particularmente gráfica sobre los peligros de permitir el sobrecompromiso. Sin embargo, también 80
me pareció interesante, así que realicé algunas pruebas.
Lo que encontré es que overcommit_ratio
afecta la RAM total disponible para TODOS los procesos. Los procesos raíz no parecen ser tratados de manera diferente a los procesos normales del usuario.
Establecer la relación en 100
o menos debería proporcionar la semántica clásica donde los valores de retorno malloc/sbrk
son confiables. Establecer relaciones más bajas de 100
lo que podría ser una forma de reservar más RAM para actividades que no son de proceso, como el almacenamiento en caché, etc.
Entonces, en mi computadora con 24 GiB de RAM, con el intercambio deshabilitado, 9 GiB en uso, top
mostrando
Mem: 24683652k total, 9207532k used, 15476120k free, 19668k buffers
Swap: 0k total, 0k used, 0k free, 241804k cached
Aquí hay algunas overcommit_ratio
configuraciones y la cantidad de RAM que mi programa ram-consumer podría tomar (tocar cada página): en cada caso, el programa salió limpiamente una vez que malloc
falló.
50 ~680 MiB
60 ~2900 MiB
70 ~5200 MiB
100 ~12000 MiB
Ejecutar varios a la vez, incluso con algunos como usuario root, no cambió la cantidad total que consumieron juntos. Es interesante que no haya podido consumir los últimos 3+ GiB más o menos; el free
no cayó mucho por debajo de lo que se muestra aquí:
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Los experimentos fueron desordenados: cualquier cosa que use malloc en el momento en que toda la RAM está en uso tiende a fallar, ya que muchos programadores son terribles al verificar fallas de malloc en C, algunas bibliotecas de colecciones populares lo ignoran por completo, y C ++ y varios otros lenguajes son incluso peor.
La mayoría de las primeras implementaciones de RAM imaginaria que vi fueron para manejar un caso muy específico, donde un solo proceso grande, digamos 51% + de memoria disponible, era necesario fork()
para exec()
algún programa de soporte, generalmente mucho, mucho más pequeño. Los sistemas operativos con semántica de copia en escritura permitirían la fork()
, pero con la condición de que si el proceso bifurcado realmente intentara modificar demasiadas páginas de memoria (cada una de las cuales tendría que ser instanciada como una nueva página independiente del gran proceso inicial) terminaría siendo asesinado. El proceso padre solo estaba en peligro si asignaba más memoria, y podía manejar el agotamiento, en algunos casos solo esperando un poco para que otro proceso muriera, y luego continuar. El proceso secundario generalmente solo se reemplazó con un programa (generalmente más pequeño) a través deexec()
y luego estaba libre de la condición.
El concepto de exceso de compromiso de Linux es un enfoque extremo para permitir fork()
que ocurra tanto como para permitir que los procesos individuales se sobreasignen masivamente. Muertes OOM-killer-causado ocurren de forma asíncrona, incluso a los programas que hacen la asignación de memoria mango con responsabilidad. Personalmente, odio el exceso de compromiso en todo el sistema en general y el asesino de Oom en particular: fomenta un enfoque de cuidado del diablo para la gestión de la memoria que infecta las bibliotecas y, a través de ellas, todas las aplicaciones que las usan.
Sugeriría establecer la proporción en 100, y tener una partición de intercambio que generalmente solo terminaría siendo utilizada por procesos enormes, que a menudo solo usan una pequeña fracción de la parte de sí mismos que se rellena en el intercambio, y por lo tanto proteja la gran mayoría de los procesos de la mala característica del OOM asesino. Esto debería mantener su servidor web a salvo de una muerte aleatoria, y si fue escrito para manejar de manera malloc
responsable, incluso a salvo de suicidarse (pero no apueste por el último).
Eso significa que estoy usando esto en /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100