Hmm, no me convencen del todo los argumentos a favor de overcommit y OOM killer... Cuando womble escribe,
"El asesino OOM sólo causa estragos si has sobrecargado tu sistema. Dale suficiente swap y no ejecutes aplicaciones que de repente decidan comerse cantidades ingentes de RAM, y no tendrás problemas".
Se trata de describir un escenario de entorno en el que el overcommit y el OOM killer no se aplican, o no actúan "realmente" (si todas las aplicaciones asignaran memoria según la necesitaran, y hubiera suficiente memoria virtual para asignar, las escrituras de memoria seguirían de cerca las asignaciones de memoria sin errores, por lo que no podríamos hablar realmente de un sistema overcommited aunque se activara una estrategia overcommit). Eso es más o menos una admisión implícita de que el overcommit y el OOM killer funcionan mejor cuando su intervención no es necesaria, lo que de alguna manera comparten la mayoría de los partidarios de esta estrategia, por lo que puedo decir (y admito que no puedo decir mucho...). Por otra parte, referirse a aplicaciones con comportamientos específicos a la hora de preasignar memoria me hace pensar que un manejo específico podría ser ajustado a nivel de distribución, en lugar de tener un enfoque por defecto basado en heurísticas (personalmente, creo que la heurística no es un enfoque muy bueno para cosas del kernel).
Por lo que respecta a la JVM, bueno, es una máquina virtual, hasta cierto punto necesita asignar todos los recursos que necesita en el arranque, para que pueda crear su entorno "falso" para sus aplicaciones, y mantener sus recursos disponibles separados del entorno del host, en la medida de lo posible. Por lo tanto, puede ser preferible que falle en el arranque, en lugar de después de un tiempo como consecuencia de una condición OOM 'externa' (causada por overcommit/OOM killer/lo que sea), o de todos modos sufriendo por tal condición que interfiere con sus propias estrategias internas de manejo de OOM (en general, una VM debería obtener cualquier recurso requerido desde el principio y el sistema anfitrión debería 'ignorarlos' hasta el final, de la misma manera que cualquier cantidad de ram física compartida con una tarjeta gráfica nunca es -y no puede ser- tocada por el SO).
Sobre Apache, dudo que tener todo el servidor ocasionalmente muerto y reiniciado sea mejor que dejar que un único hijo, junto con una única conexión, falle desde su (= del hijo/de la conexión) comienzo (como si fuera una instancia completamente nueva de la JVM creada después de que otra instancia funcionara durante un tiempo). Supongo que la mejor "solución" podría depender de un contexto específico. Por ejemplo, considerando un servicio de comercio electrónico, podría ser preferible tener, a veces, unas pocas conexiones a la cesta de la compra fallando aleatoriamente en lugar de perder todo el servicio, con el riesgo, por ejemplo, de interrumpir la finalización de un pedido en curso, o (tal vez peor) un proceso de pago, con todas las consecuencias del caso (tal vez inofensivo, pero tal vez perjudicial - y con seguridad, cuando surgieran problemas, estos serían peores que una condición de error irreproducible para fines de depuración).
De la misma manera, en una estación de trabajo, el proceso que consume más recursos, y por lo tanto la primera opción para el OOM killer, podría ser una aplicación intensiva en memoria, como un transcodificador de vídeo, o un software de renderizado, probablemente la única aplicación que el usuario quiere que no sea tocada. Estas consideraciones me sugieren que la política por defecto del OOM killer es demasiado agresiva. Utiliza un enfoque de "peor ajuste" que es de alguna manera similar al de algunos sistemas de ficheros (el OOMK intenta liberar tanta memoria como puede, mientras reduce el número de subprocesos muertos, con el fin de prevenir cualquier otra intervención en poco tiempo, así como un fs puede asignar más espacio en disco del realmente necesario para un determinado fichero, para prevenir cualquier otra asignación si el fichero crece y así prevenir la fragmentación, hasta cierto punto).
Sin embargo, creo que una política opuesta, como un enfoque de "mejor ajuste", podría ser preferible, para liberar la memoria exacta que se necesita en un momento determinado, y no molestarse con procesos "grandes", que bien podrían estar desperdiciando memoria, pero también podrían no estarlo, y el núcleo no puede saberlo (hmm, Puedo imaginar que mantener un registro de los accesos a las páginas y el tiempo podría indicar si un proceso está asignando memoria que ya no necesita, para adivinar si un proceso está malgastando memoria o simplemente usando mucha, pero los retrasos en los accesos deberían ser ponderados en ciclos de cpu para distinguir entre un malgasto de memoria y una pérdida de memoria. y aplicación intensiva en cpu, pero, aunque potencialmente inexacta, una heurística de este tipo podría tener una sobrecarga excesiva).
Además, puede que no sea cierto que matar el menor número posible de procesos sea siempre una buena elección. Por ejemplo, en un entorno de escritorio (pensemos en un nettop o un netbook con recursos limitados, por ejemplo) un usuario puede estar ejecutando un navegador con varias pestañas (por lo tanto, consume memoria - supongamos que esta es la primera opción para el OOMK), además de algunas otras aplicaciones (un procesador de textos con datos no guardados, un cliente de correo, un lector de pdf, un reproductor multimedia, ...), además de algunos demonios (del sistema), además de algunas instancias del gestor de archivos. Ahora, ocurre un error OOM, y el OOMK elige matar el navegador mientras el usuario está haciendo algo considerado 'importante' en la red... el usuario se decepcionaría. Por otro lado, cerrar las pocas instancias del gestor de archivos que están en reposo podría liberar la cantidad exacta de memoria necesaria y mantener el sistema no sólo funcionando, sino funcionando de una manera más fiable.
De todos modos, creo que el usuario debería poder decidir por sí mismo qué hacer. En un sistema de escritorio (=interactivo), eso debería ser relativamente fácil de hacer, siempre que se reserven recursos suficientes para pedir al usuario que cierre cualquier aplicación (pero incluso cerrar unas cuantas pestañas podría ser suficiente) y se ocupe de su elección (una opción podría consistir en crear un archivo de intercambio adicional, si hay espacio suficiente). Para los servicios (y en general), también consideraría otras dos posibles mejoras: una es el registro de los OOM killer intervents, así como de los procesos que se inician o bifurcan de tal manera que el fallo pueda ser fácilmente depurado (por ejemplo, una API podría informar al proceso que emite la creación de un nuevo proceso o bifurcación - así, un servidor como Apache, con un parche adecuado, podría proporcionar un mejor registro de ciertos errores); esto podría hacerse independientemente del overcommit/OOMK que se esté produciendo; en segundo lugar, pero no por importancia, se podría establecer un mecanismo para afinar el algoritmo OOMK - sé que es posible, hasta cierto punto, definir una política específica proceso por proceso, pero yo apuntaría a un mecanismo de configuración 'centralizado', basado en una o más listas de nombres de aplicaciones (o ids) para identificar procesos relevantes y darles un cierto grado de importancia (según los atributos listados); Tal mecanismo debería (o al menos podría) ser estratificado, de modo que podría haber una lista de alto nivel definida por el usuario, una lista definida por el sistema (distribución), y entradas definidas por la aplicación (de bajo nivel) (así, por ejemplo, un gestor de archivos DE podría instruir al OOMK para matar de forma segura cualquier instancia, ya que un usuario puede reabrirla de forma segura para acceder a la vista del archivo perdido - mientras que cualquier operación importante, como mover/copiar/crear datos podría ser delegada a un proceso más "privilegiado").
Además, se podría proporcionar una API que permitiera a las aplicaciones subir o bajar su nivel de "importancia" en tiempo de ejecución (con respecto a la gestión de la memoria e independientemente de la prioridad de ejecución), de forma que, por ejemplo, un procesador de texto pudiera empezar con una "importancia" baja, pero subirla a medida que se guardan algunos datos antes de volcarlos a un fichero, o se realiza una operación de escritura, y volver a bajar la importancia una vez que dicha operación termine (análogamente, un gestor de ficheros podría cambiar de nivel cuando pasara de sólo leer ficheros a tratar con datos y viceversa, en lugar de usar procesos separados, y Apache podría dar diferentes niveles de importancia a diferentes hijos, o cambiar el estado de un hijo de acuerdo con alguna política decidida por los administradores del sistema y expuesta a través de la configuración de Apache - o de cualquier otro tipo de servidor). Por supuesto, tal API podría y sería abusada/mal usada, pero creo que es una preocupación menor comparada con el kernel matando procesos arbitrariamente para liberar memoria sin ninguna información relevante sobre lo que está pasando en el sistema (y el consumo de memoria/tiempo de creación o similares no son lo suficientemente relevantes o "validadores" para mí) - sólo los usuarios, administradores y escritores de programas pueden realmente determinar si un proceso es "todavía necesario" por alguna razón, cuál es la razón, y/o si la aplicación está en un estado que lleva a la pérdida de datos u otros daños/problemas si se mata; Sin embargo, se podrían hacer algunas suposiciones, por ejemplo, buscar recursos de cierto tipo (descriptores de archivo, sockets de red, etc.) adquiridos por un proceso y con recursos pendientes. ) adquiridos por un proceso y con operaciones pendientes podría decir si un proceso debería estar en un "estado" superior al establecido, o si su estado "autoestablecido" es superior al necesario y puede ser reducido (enfoque agresivo, a menos que sea sustituido por elecciones del usuario, como forzar un cierto estado, o pedir - a través de las listas que he mencionado antes - que se respeten las elecciones de la aplicación).
O, simplemente, evitar el overcommitting y dejar que el kernel haga justo lo que un kernel debe hacer, asignar recursos (pero no rescatarlos arbitrariamente como hace el OOM killer), programar procesos, prevenir starvations y deadlocks (o rescatarlos de ellos), asegurar el preemption completo y la separación de espacios de memoria, etc...
También dedicaría algunas palabras más a los planteamientos de compromiso excesivo. De otras discusiones he sacado la idea de que una de las principales preocupaciones sobre overcommit (tanto como razón para quererlo como fuente de posibles problemas) consiste en el manejo de forks: honestamente, no sé cómo se implementa exactamente la estrategia copy-on-write, pero creo que cualquier política agresiva (u optimista) podría mitigarse con una estrategia de localidad similar a swap. Es decir, en lugar de simplemente clonar (y ajustar) las páginas de código y las estructuras de programación de un proceso bifurcado, se podrían copiar algunas otras páginas de datos antes de una escritura real, eligiendo entre aquellas páginas a las que el proceso padre ha accedido para escribir con más frecuencia (es decir, usando un contador para las operaciones de escritura).
Todo, por supuesto, IMHO.