GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo mantener el código ejecutable en la memoria incluso bajo presión de memoria? en Linux

ADVERTENCIA: No use este parche si tiene habilitado el intercambio, porque dos usuarios informaron efectos peores. ¡Solo probé este parche con el intercambio deshabilitado en el kernel! (es decir, CONFIG_SWAP no está configurado)

Hasta nuevo aviso (o a alguien se le ocurre algo mejor), estoy usando (y funciona, para mí) el siguiente parche para evitar que el disco se apague o se congele el sistema operativo cuando esté a punto de quedarse sin memoria y, por lo tanto, el OOM-killer se activa lo antes posible (máx. 1 segundo):

revision 3
preliminary patch to avoid disk thrashing (constant reading) under memory pressure before OOM-killer triggers
more info: https://gist.github.com/constantoverride/84eba764f487049ed642eb2111a20830

diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 32699b2..7636498 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -208,7 +208,7 @@ enum lru_list {

 #define for_each_lru(lru) for (lru = 0; lru < NR_LRU_LISTS; lru++)

-#define for_each_evictable_lru(lru) for (lru = 0; lru <= LRU_ACTIVE_FILE; lru++)
+#define for_each_evictable_lru(lru) for (lru = 0; lru <= LRU_INACTIVE_FILE; lru++)

 static inline int is_file_lru(enum lru_list lru)
 {
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 03822f8..1f3ffb5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2086,9 +2086,9 @@ static unsigned long shrink_list(enum lr
                 struct scan_control *sc)
 {
    if (is_active_lru(lru)) {
-       if (inactive_list_is_low(lruvec, is_file_lru(lru),
-                    memcg, sc, true))
-           shrink_active_list(nr_to_scan, lruvec, sc, lru);
+       //if (inactive_list_is_low(lruvec, is_file_lru(lru),
+       //           memcg, sc, true))
+       //  shrink_active_list(nr_to_scan, lruvec, sc, lru);
        return 0;
    }

@@ -2234,7 +2234,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,

    anon  = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, MAX_NR_ZONES) +
        lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, MAX_NR_ZONES);
-   file  = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES) +
+   file  = //lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES) +
        lruvec_lru_size(lruvec, LRU_INACTIVE_FILE, MAX_NR_ZONES);

    spin_lock_irq(&pgdat->lru_lock);
@@ -2345,7 +2345,7 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
             sc->priority == DEF_PRIORITY);

    blk_start_plug(&plug);
-   while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
+   while (nr[LRU_INACTIVE_ANON] || //nr[LRU_ACTIVE_FILE] ||
                    nr[LRU_INACTIVE_FILE]) {
        unsigned long nr_anon, nr_file, percentage;
        unsigned long nr_scanned;
@@ -2372,7 +2372,8 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
         * stop reclaiming one LRU and reduce the amount scanning
         * proportional to the original scan target.
         */
-       nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE];
+       nr_file = nr[LRU_INACTIVE_FILE] //+ nr[LRU_ACTIVE_FILE]
+           ;
        nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON];

        /*
@@ -2391,7 +2392,8 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
            percentage = nr_anon * 100 / scan_target;
        } else {
            unsigned long scan_target = targets[LRU_INACTIVE_FILE] +
-                       targets[LRU_ACTIVE_FILE] + 1;
+                       //targets[LRU_ACTIVE_FILE] + 
+                       1;
            lru = LRU_FILE;
            percentage = nr_file * 100 / scan_target;
        }
@@ -2409,10 +2411,12 @@ static void shrink_node_memcg(struct pgl
        nr[lru] = targets[lru] * (100 - percentage) / 100;
        nr[lru] -= min(nr[lru], nr_scanned);

+       if (LRU_FILE != lru) { //avoid this block for LRU_ACTIVE_FILE
        lru += LRU_ACTIVE;
        nr_scanned = targets[lru] - nr[lru];
        nr[lru] = targets[lru] * (100 - percentage) / 100;
        nr[lru] -= min(nr[lru], nr_scanned);
+       }

        scan_adjusted = true;
    }

Desafortunadamente, las pestañas anteriores se convirtieron en espacios, por lo que si desea el parche sin formato, está aquí.

Lo que hace este parche no es desalojar el Active(file) páginas cuando está bajo presión de memoria y por lo tanto no causa kswapd0 (pero visto en iotop como cada programa en sí) para volver a leer las páginas ejecutables de cada proceso en ejecución cada vez que haya un cambio de contexto para permitir que el programa (continúe) ejecutándose. Por lo tanto, se evita una tonelada de golpes de disco y el sistema operativo no se congela en un rastreo.

Lo anterior se probó con el kernel 4.18.5 (y ahora probando 4.18.7) dentro de dom0 de Qubes OS 4.0 (Fedora 25) y todas las máquinas virtuales (Fedora 28) que estoy usando.

Para la primera versión de este parche, que también funciona (aparentemente), consulte el EDIT sobre la misma pregunta de la que esta es una respuesta.

ACTUALIZACIÓN: Después de usar este parche durante un tiempo en una computadora portátil ArchLinux con 16 GB de RAM (menos 512 MB reservados para la tarjeta gráfica integrada) y sin intercambio (también deshabilitado en el kernel), puedo decir que el sistema puede quedarse sin memoria antes que sin el parche le9d. (rev. 3), por lo que OOM-killer se activa para Xorg o chromium u otros cuando no lo habría hecho sin el parche. Y como mitigación, eso parece funcionar para mí hasta ahora, he estado ejecutando echo 1 > /proc/sys/vm/drop_caches siempre que el Active(file) el número en /proc/meminfo es superior a 2G, también conocido como 2000000 KB (por ejemplo, obtenga el número de KB a través de este código:grep 'Active(file):' /proc/meminfo|tr -d ' '|cut -f2 -d:|sed 's/kB//' ) y haciendo esta comprobación con un sleep 5 después. Pero últimamente, para compilar firefox-hg en /tmp, que es tmpfs y que, en última instancia, usa 12G y me aseguro de que no se elimine OOM, he estado usando 500000 en lugar de 2000000 KB. Seguro que es mejor que congelar todo el sistema (es decir, sin le9d.patch), lo que habría sucedido en este caso de compilación de Firefox. Sin esta verificación, Active(file) no va más allá de 4G, pero eso es suficiente para OOM-kill Xorg si algo quiere más memoria, como en este caso de compilación de Firefox o incluso cuando se copian muchos gigabytes a través del comando de medianoche (si no recuerdo mal).


El parámetro memory.min en el controlador de memoria cgroups-v2 debería ayudar.

A saber, permítanme citar:

"Protección de memoria dura. Si el uso de memoria de un cgroup está dentro de su límite mínimo efectivo, la memoria del cgroup no se recuperará bajo ninguna condición. Si no hay memoria recuperable desprotegida disponible, se invoca el eliminador de OOM".

https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html


Para responder a la pregunta, aquí hay un parche simple/preliminar para no desalojar a Active(file) (como se ve en /proc/meminfo ) si tiene menos de 256 MiB, parece funcionar bien (sin problemas de disco) con linux-stable 5.2.4:

diff --git a/mm/vmscan.c b/mm/vmscan.c
index dbdc46a84f63..7a0b7e32ff45 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2445,6 +2445,13 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
            BUG();
        }

+    if (NR_ACTIVE_FILE == lru) {
+      long long kib_active_file_now=global_node_page_state(NR_ACTIVE_FILE) * MAX_NR_ZONES;
+      if (kib_active_file_now <= 256*1024) {
+        nr[lru] = 0; //don't reclaim any Active(file) (see /proc/meminfo) if they are under 256MiB
+        continue;
+      }
+    }
        *lru_pages += size;
        nr[lru] = scan;
    }

Tenga en cuenta que algunos aún-por-encontrarse la regresión en el kernel 5.3.0-rc4-gd45331b00ddb provocará un congelamiento del sistema (sin problemas de disco y sysrq seguirá funcionando) incluso sin este parche.

(Cualquier nuevo desarrollo relacionado con esto debería estar ocurriendo aquí).


Linux
  1. Cómo borrar la caché de memoria en Linux

  2. Linux:¿cómo probar si un binario de Linux se compiló como código independiente de la posición?

  3. Cómo usar FTP en Linux para transferir archivos

  4. Cómo usar el comando tar en Linux

  5. Cómo usar la redirección de comandos en Linux

Cómo borrar la memoria de intercambio en Linux

Cómo deshabilitar permanentemente el intercambio en Linux

¿Cómo hacer un archivo ejecutable en la terminal de Linux?

¿Cómo funciona el intercambio de memoria en Linux?

Cómo mantener actualizado Rocky Linux 8

¿Cómo puedo perfilar el código C++ que se ejecuta en Linux?