GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie kann ausführbarer Code auch unter Speicherdruck im Speicher gehalten werden? unter Linux

WARNUNG: Verwenden Sie diesen Patch nicht, wenn Sie Swap aktiviert haben, da zwei Benutzer von schlimmeren Auswirkungen berichteten. Ich habe diesen Patch nur mit im Kernel deaktiviertem Swap getestet! (dh CONFIG_SWAP ist nicht gesetzt)

Bis auf Weiteres (oder jemand fällt etwas Besseres ein) verwende ich (und es funktioniert bei mir) den folgenden Patch, um ein Disk-Thrashing / OS-Freeze zu vermeiden, wenn Out Of Memory und damit der OOM-Killer ausgeführt wird löst so schnell wie möglich aus (max. 1 Sek.):

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

Leider wurden die obigen Tabulatoren in Leerzeichen umgewandelt, also wenn Sie den rohen Patch wollen, ist er hier.

Dieser Patch entfernt nicht den Active(file) Seiten unter Speicherdruck und verursachen somit nicht kswapd0 (aber gesehen in iotop wie jedes Programm selbst), um die ausführbaren Seiten jedes laufenden Prozesses bei jedem Kontextwechsel erneut zu lesen, damit das Programm (weiter) ausgeführt werden kann. So wird eine Menge Festplatten-Thrashing vermieden und das Betriebssystem friert nicht in einem Crawl ein.

Das Obige wurde mit Kernel 4.18.5 (und testet jetzt 4.18.7) in Qubes OS 4.0 's dom0 (Fedora 25) und allen VMs (Fedora 28), die ich verwende, getestet.

Für die erste Version dieses Patches, die (anscheinend) auch funktioniert, siehe EDIT auf die Frage, dass dies eine Antwort von ist.

AKTUALISIERUNG: Nachdem ich diesen Patch eine Weile auf einem ArchLinux-Laptop mit 16 GB RAM (minus 512 MB reserviert für integrierte Grafikkarte) und ohne Swap (auch im Kernel deaktiviert) verwendet habe, kann ich sagen, dass dem System früher der Speicher ausgehen kann als ohne den le9d.patch (Rev. 3) und so OOM-Killer-Trigger für Xorg oder Chromium oder andere, die es ohne den Patch nicht gegeben hätte. Und als Abhilfe, das scheint bisher für mich zu funktionieren, habe ich echo 1 > /proc/sys/vm/drop_caches ausgeführt immer wenn Active(file) Nummer in /proc/meminfo ist über 2G alias 2000000 KB (z. B. erhalten Sie die Anzahl der KB über diesen Code:grep 'Active(file):' /proc/meminfo|tr -d ' '|cut -f2 -d:|sed 's/kB//' ) und diese Überprüfung mit einem sleep 5 durchführen danach. Aber in letzter Zeit habe ich 500000 statt 2000000 KB verwendet, um firefox-hg in /tmp zu kompilieren, das tmpfs ist und letztendlich 12G verwendet, und um sicherzustellen, dass es nicht durch OOM getötet wird. Es ist sicher besser, als das gesamte System einzufrieren (dh ohne le9d.patch), was in diesem Fall der Firefox-Kompilierung passiert wäre. Ohne diese Prüfung Active(file) geht nicht höher als 4G, aber das reicht aus, um Xorg durch OOM zu töten, wenn etwas mehr Speicher benötigt, wie in diesem Fall der Firefox-Kompilierung oder sogar wenn nur viele Gigabyte über den Mitternachtskommandanten kopiert werden (wenn ich mich richtig erinnere).


Der Parameter memory.min im cgroups-v2-Speichercontroller sollte helfen.

Lassen Sie mich nämlich zitieren:

"Schutz des Festplattenspeichers. Wenn die Speichernutzung einer Kontrollgruppe innerhalb ihrer effektiven Mindestgrenze liegt, wird der Speicher der Kontrollgruppe unter keinen Umständen zurückgefordert. Wenn kein ungeschützter, zurückgewinnbarer Speicher verfügbar ist, wird der OOM-Killer aufgerufen."

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


Um die Frage zu beantworten, hier ist ein einfacher/vorläufiger Patch, um Active(file) nicht zu entfernen (wie in /proc/meminfo zu sehen ) Wenn es weniger als 256 MiB sind, scheint das mit Linux-Stable 5.2.4 zu funktionieren (kein Festplatten-Thrashing):

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

Beachten Sie, dass einige noch zu finden sind Regression auf Kernel 5.3.0-rc4-gd45331b00ddb wird ein Einfrieren des Systems verursachen (ohne Festplatten-Thrashing und sysrq wird immer noch funktionieren), auch ohne diesen Patch.

(alle diesbezüglichen neuen Entwicklungen sollten hier stattfinden.)


Linux
  1. So löschen Sie den Speichercache in Linux

  2. Wie kann man eine ausführbare Linux-Datei zerlegen, ändern und dann wieder zusammensetzen?

  3. Wie disassembliere ich eine ausführbare Binärdatei unter Linux, um den Assemblercode zu erhalten?

  4. So ermitteln Sie die Benutzerspeichernutzung in Linux

  5. Wie wird die Speichernutzung in Linux gemeldet?

So löschen Sie den Auslagerungsspeicher unter Linux

So deaktivieren Sie Swap dauerhaft unter Linux

Wie mache ich eine Datei im Linux-Terminal ausführbar?

Wie funktioniert Swap-Speicher in Linux?

So halten Sie Rocky Linux 8 auf dem neuesten Stand

Wie kann ich C++-Code profilieren, der unter Linux ausgeführt wird?