Целью здесь является сохранение исполняемого кода каждого запущенного процесса в памяти во время нехватки памяти в Linux.
В Linux я могу мгновенно (1 секунда) вызвать высокое давление памяти и вызвать OOM-killer с помощью
stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 + 4000;}' < /proc/meminfo)k --vm-keep -m 4 --timeout 10s
(код от здесь )
с максимальной оперативной памятью 24000 МБ внутри операционной системы Qubes R4.0 Fedora 28. EDIT4: Возможно, уместно, и все же я забыл упомянуть, это тот факт, что у меня не включен своп (т. Е. CONFIG_SWAP
не установлен)
отчеты dmesg:
[ 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
Интересные части active_file:94 inactive_file:72
они в килобайтах и очень малы.
Проблема здесь заключается в том, что во время этого периода нехватки памяти исполняемый код перечитывается с диска, вызывая перегрузку диска, что приводит к зависанию ОС . (но в приведенном выше случае это происходит не более 1 секунды)
Я вижу интересный код в ядре 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;
}
}
Я думаю, что если кто-то может указать, как это изменить, чтобы вместо give them one more trip around the active list
мы получили значение give them infinite trips around the active list
, то работа должна быть выполнена. Или, может быть, есть другой способ?
Я могу исправлять и тестировать собственное ядро. У меня просто нет ноу-хау относительно того, что нужно изменить в коде, чтобы всегда сохранять активный исполняемый код в памяти (что, на мой взгляд, позволило бы избежать перегрузки диска).
РЕДАКТИРОВАТЬ: Вот что я получил до сих пор (применяется поверх ядра 4.18.5):
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;
}
Также можно увидеть здесь на github, потому что в приведенном выше коде вкладки превращаются в пробелы! ( mirror1 , mirror2 )
Я тестировал вышеупомянутый патч (на максимальной оперативной памяти 4000 МБ, да на 20 ГБ меньше, чем раньше!) Даже с известной компиляцией Firefox, которая приводила диск в постоянное замораживание, и этого больше не происходит (oom-killer почти мгновенное уничтожение нарушающего процесса (ов), также с помощью приведенной выше команды stress
, которая теперь дает:
[ 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
Это active_file:26925 inactive_file:76
, почти 27 мегабайт активного файла ...
Итак, я не знаю, насколько это хорошо. Сохраняю ли я все активные файлы вместо исполняемых файлов в памяти? Во время компиляции Firefox у меня было примерно 500 мг Active(file)
( EDIT2: , но это соответствует: cat /proc/meminfo|grep -F -- 'Active(file)'
, который показывает значение, отличное от приведенного выше active_file:
из dmesg !!!), что вызывает у меня сомнения это были только exes / libs ...
Может быть, кто-то может подсказать, как сохранить ТОЛЬКО исполняемый код? (Если это не то, что уже происходит)
Мысли?
EDIT3: с вышеприведенным патчем, возможно, необходимо (периодически?) Запускать sudo sysctl vm.drop_caches=1
для освобождения некоторой устаревшей памяти (?), Так что если я вызову stress
после компиляции Firefox Я получаю: active_file:142281 inactive_file:0 isolated_file:0
(142megs), затем удаляю файловые кэши (другой способ: echo 1|sudo tee /proc/sys/vm/drop_caches
), затем снова запускаю stress
, я получаю: active_file:22233 inactive_file:160 isolated_file:0
(22megs) - я не уверен ...
Результаты без вышеуказанного патча: здесь
Результаты с вышеуказанным патчем: здесь