it-swarm.com.de

Wie kann man ausführbaren Code auch unter Druck speichern? in Linux

Ziel ist es, den ausführbaren Code jedes laufenden Prozesses während des Speicherdrucks in Linux im Speicher zu halten.
Unter Linux kann ich sofort (1 Sekunde) einen hohen Speicherdruck verursachen und den OOM-Killer durch stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 + 4000;}' < /proc/meminfo)k --vm-keep -m 4 --timeout 10s (Code aus hier ) Auslösen. mit 24000 MB max RAM innerhalb einer Qubes OS R4.0 Fedora 28 AppVM. EDIT4: Vielleicht relevant, und ich habe noch vergessen zu erwähnen, ist die Tatsache, dass ich keinen Swap aktiviert habe (dh. CONFIG_SWAP ist nicht gesetzt). 

dmesg berichtet: 

[  867.746593] Mem-Info:
[  867.746607] active_anon:1390927 inactive_anon:4670 isolated_anon:0
                active_file:94 inactive_file:72 isolated_file:0
                unevictable:13868 dirty:0 writeback:0 unstable:0
                slab_reclaimable:5906 slab_unreclaimable:12919
                mapped:1335 shmem:4805 pagetables:5126 bounce:0
                free:40680 free_pcp:978 free_cma:0

Die interessanten Teile sind active_file:94 inactive_file:72, sie sind in Kilobyte und sind sehr niedrig. 

Das Problem hierbei ist, dass während dieser Zeit des Speicherdrucks der ausführbare Code erneut von der Festplatte gelesen wird, was zu Plattenverwerfungen führt, die zu eingefrorenes OS führen. (aber im obigen Fall passiert das nur für weniger als 1 Sekunde) 

Ich sehe einen interessanten Code im Kernel mm/vmscan.c:

        if (page_referenced(page, 0, sc->target_mem_cgroup,
                            &vm_flags)) {
                nr_rotated += hpage_nr_pages(page);
                /*
                 * Identify referenced, file-backed active pages and
                 * give them one more trip around the active list. So
                 * that executable code get better chances to stay in
                 * memory under moderate memory pressure.  Anon pages
                 * are not likely to be evicted by use-once streaming
                 * IO, plus JVM can create lots of anon VM_EXEC pages,
                 * so we ignore them here.
                 */
                if ((vm_flags & VM_EXEC) && page_is_file_cache(page)) {
                        list_add(&page->lru, &l_active);
                        continue;
                }
        }

Ich denke, wenn jemand sagen könnte, wie man das ändern kann, anstatt give them one more trip around the active list den Code give them infinite trips around the active list zu bekommen, dann sollte der Job erledigt sein. Oder gibt es vielleicht einen anderen Weg? 

Ich kann einen angepassten Kernel patchen und testen. Ich habe einfach nicht das Know-how, was im Code geändert werden muss, um immer aktiven ausführbaren Code im Speicher zu behalten (was meines Erachtens Festplatten-Thrashing vermeiden würde).

EDIT: Hier ist was ich bis jetzt gearbeitet habe (auf Kernel 4.18.5 angewendet): 

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

Auch here auf Github gesehen, weil in dem obigen Code Tabs in Leerzeichen umgewandelt wurden! ( mirror1 , mirror2 )
Ich habe den obigen Patch getestet (auf 4000 MB max RAM jetzt, ja 20 G weniger als zuvor!), Selbst mit einer Firefox-Compilation, die bekanntermaßen die Festplatte in ein permanentes Einfrieren des Betriebssystems brachte. und es passiert nicht mehr (oom-killer tötet fast augenblicklich den beleidigenden Prozess), auch mit dem obigen Befehl stress, der jetzt Folgendes ergibt: 

[  745.830511] Mem-Info:
[  745.830521] active_anon:855546 inactive_anon:20453 isolated_anon:0
                active_file:26925 inactive_file:76 isolated_file:0
                unevictable:10652 dirty:0 writeback:0 unstable:0
                slab_reclaimable:26975 slab_unreclaimable:13525
                mapped:24238 shmem:20456 pagetables:4028 bounce:0
                free:14935 free_pcp:177 free_cma:0

Das ist active_file:26925 inactive_file:76, fast 27 MB aktive Datei ...
Ich weiß nicht, wie gut das ist. Behalte ich alle aktiven Dateien statt nur ausführbare Dateien im Speicher? Während der Firefox-Kompilierung hatte ich ungefähr 500meg von Active(file) ( EDIT2: , aber das entspricht: cat /proc/meminfo|grep -F -- 'Active(file)', die einen anderen Wert als den obigen active_file: von dmesg !!! zeigt), was mich bezweifelt, dass es nur Exes/Libs waren ...
Vielleicht kann jemand vorschlagen, NUR ausführbaren Code zu behalten (falls dies nicht bereits der Fall ist)
Gedanken? 

EDIT3: Mit dem obigen Patch scheint es vielleicht notwendig, (periodisch?) Sudo sysctl vm.drop_caches=1 auszuführen, um veralteten Speicher freizugeben (?), Sodass ich, wenn ich stress nach einer Firefox-Compilierung aufrufe, Folgendes erhalte: active_file:142281 inactive_file:0 isolated_file:0 (142megs) dann lösche Datei-Caches (eine andere Möglichkeit: echo 1|Sudo tee /proc/sys/vm/drop_caches) und führe stress erneut aus. Ich erhalte: active_file:22233 inactive_file:160 isolated_file:0 (22megs) - ich bin mir nicht sicher ... 

Ergebnisse ohne den obigen Patch: hier
Ergebnisse mit dem obigen Patch: hier

8
Marcus Linsner

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

Bis auf weiteres (oder jemandem fällt etwas Besseres ein), verwende ich (und es funktioniert für mich) das folgende patch , um zu verhindern, dass Festplatten ausfallen oder das Betriebssystem einfriert, wenn Out Of Memory ausgeführt wird und somit löst der OOM-Killer 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 werden die obigen Registerkarten in Leerzeichen konvertiert. Wenn Sie also den unformatierten Patch verwenden möchten, ist er hier

Mit diesem Patch werden die Active(file)-Seiten nicht gelöscht, wenn sie unter Speicherdruck stehen. Daher wird kswapd0 (jedoch in iotop als jedes Programm selbst gesehen) nicht dazu veranlasst, die ausführbaren Seiten jedes laufenden Prozesses jedes Mal neu zu lesen, wenn ein Kontextwechsel angezeigt wird. damit das Programm (weiterhin) ausgeführt werden kann. Auf diese Weise wird eine Menge Disk-Thrashing vermieden, und das Betriebssystem friert nicht zu einer Durchforstung ein. 

Das obige wurde mit Kernel 4.18.5 (und jetzt 4.18.7) in Domos (0) von Qubes OS 4.0 (Fedora 25) und allen VMs (Fedora 28) getestet, die ich verwende. 

Für die erste Version dieses Patches, die ebenfalls (anscheinend) ebenfalls funktioniert, sehen Sie in der EDIT genau die Frage, auf die dies eine Antwort ist. 

UPDATE: Nachdem Sie diesen Patch eine Weile auf einem ArchLinux-Laptop mit 16G RAM (minus 512M für integrierte Grafikkarte) und keinen Swap (auch im Kernel deaktiviert) verwendet haben, kann ich das sagen Dem System kann der Speicher früher ausgehen als ohne le9d.patch (rev. 3). Daher löst OOM-killer Xorg oder Chrom oder anderes aus, wenn es ohne den Patch nicht möglich wäre. Und als Milderung, das scheint für mich bisher zu funktionieren, habe ich echo 1 > /proc/sys/vm/drop_caches ausgeführt, wann immer die Active(file)-Nummer in/proc/meminfo über 2G oder 2000000 KB (z. B. KB-Nummer über diesen Code: grep 'Active(file):' /proc/meminfo|tr -d ' '|cut -f2 -d:|sed 's/kB//') und Überprüfen Sie dies anschließend mit einem sleep 5. Um firefox-hg in/tmp zu kompilieren, das ist tmpfs und das letztendlich 12G verwendet, um sicherzustellen, dass OOM nicht getötet wird, habe ich 500000 anstelle von 2000000 KB verwendet. Es ist sicher besser, als das gesamte System einzufrieren (dh ohne le9d.patch), was in diesem Firefox-Compilierungsfall geschehen wäre. Ohne diese Überprüfung geht Active(file) nicht höher als 4G, aber das reicht aus, um XOM zu beenden, wenn etwas mehr Speicherplatz benötigt, wie in diesem Firefox-Compilierungsfall oder sogar, wenn nur viele Gigabytes über den Mitternachtskommandanten kopiert werden (wenn ich mich recht erinnere). 

2
Marcus Linsner

Um die Frage zu beantworten, ist hier ein einfacher/vorläufiger Patch, mit dem Active(file) nicht entfernt werden kann (wie in /proc/meminfo) wenn es weniger als 256 MiB ist, scheint das in Ordnung zu sein (kein Disk Thrashing) mit 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;
    }

Beachten Sie, dass einige noch zu finden regression on Kernel 5.3.0-rc4-Gd45331b00ddb führt auch ohne diesen Patch zu einem Systemabsturz (ohne Festplattenüberlastung und sysrq funktioniert weiterhin).

(Alle neuen Entwicklungen in diesem Zusammenhang sollten stattfinden hier. )

1
user11509478

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

Ich zitiere nämlich:

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

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

0