当前位置: 首页 > 面试题库 >

如何即使在内存压力下也将可执行代码保留在内存中?在Linux中

葛兴发
2023-03-14
问题内容

目的是在内存不足的情况下,在Linux中将每个正在运行的进程的可执行代码保留在内存中。
在Linux中,我可以立即(1秒)造成高内存压力,并通过Qubes OS R4.0 Fedora 28 AppVM内具有24000MB最大RAM
stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 + 4000;}' < /proc/meminfo)k --vm-keep -m 4 --timeout 10s(此处的代码)触发OOM杀手 。
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它们以千字节为单位,并且非常低。

这里的问题是,在那段内存压力期间,正在从磁盘重新读取可执行代码,从而导致磁盘抖动,从而导致OS冻结。(但在上述情况下,它只会发生不到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)
我已经测试了上述补丁(现在最大内存为4000MB,比以前少20G!),即使使用了已知的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编译过程中,我有500meg的Active(file)
EDIT2: 但这是根据:与dmesg cat /proc/meminfo|grep -F -- 'Active(file)'相比,它显示的值不同于上面的值active_file:!!!)这使我怀疑,它仅仅是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)-我不确定…

结果没有上述补丁:此
结果与上述补丁:这里


问题答案:

要回答这个问题,这是一个简单的/初步的补丁程序,如果它小于256
MiB,则不驱逐Active(file)(如所示/proc/meminfo),对于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;
    }

请注意,即使没有此修补程序,对内核5.3.0-rc4-gd45331b00ddb的一些
尚待发现的
回归也会导致系统冻结(磁盘不抖动,并且sysrq仍然有效)。

(与此有关的任何新发展都应该在这里发生。)



 类似资料:
  • 问题内容: 是否可以对Android系统进行压力测试,以检查如果可用内存减少(以及因此杀死了哪些应用程序,…)会发生什么情况。 我目前有一个测试应用程序,该应用程序会定期在向量中分配10MB。但是,抛出OutOfMemory异常达到500MB。但是被测系统没有受到足够的影响。我需要获取更多的内存。 是否有任何已知的库/程序要使用,或者有其他任何方法可以使应用程序使用超过500MB的内存。 补充:我

  • 问题内容: 一个的类上堆和参考变量指向它创建。 如果我写的时候没看错 类的对象在堆上创建并指向它。在堆中,我们有两个单独的对象,其中包含它们自己的实例变量。 但是如果我写 还有两个将在堆上创建,一个用于,另一个用于。但仅提供参考 即可。谁指的是堆外层?如果没有任何引用引用它,那么它应该有资格进行垃圾回收,这将影响的使用。 问题答案: 内部类包含对其外部类实例的隐藏引用。如果没有其他引用,则该隐藏引

  • 我正在尝试将一个xml文件保存到Android的内部存储中。但是,该文件没有得到保留。每次我重新启动模拟器时,该文件都会是空的。只有当我在应用程序中手动选择向其写入内容时,该文件才会被写入内容。然后,如果我关闭应用程序或其他什么,文件内容会被保留。但是,当我关闭模拟器时,文件会在那里,但是空的。 因此,我不确定我是否正确地保存了它。 请看看我的代码,也许它有问题,或者它与我的Android模拟器的

  • 问题内容: 如果我在python中有一个列表(或数组,字典…),它可能会超出可用的内存地址空间,(32位python)有哪些选项和相对速度?(除了不使列表变大之外)列表 可能 超出内存,但我无法事先知道。一旦开始超过75%,我将不再希望将该列表保留在内存中(或者无论如何都不会保留新项目),有没有办法在中途转换为基于文件的方法? 最佳(快进和快出)文件存储选项是什么? 只需要存储一个简单的数字列表。

  • 问题内容: 我使用以下代码在C#中实例化PhantomJSDriver: 并用以下方法清理它: 进程应该退出还是留在内存中?如果应该保留在Windows 7任务管理器中可见的内存中,我可以通过编程方式将其杀死吗?我是不是该? 问题答案: 直接回答,不应该用于清理实例。为了进行适当的清理,我们必须使用。 :我认为已弃用。 :用于关闭当前页面或具有焦点的浏览器(如果它是唯一的页面/选项卡)。 :它用于

  • 问题内容: Windows具有VirtualAlloc,它允许您保留地址空间的连续区域,但实际上不使用任何物理内存。稍后,当您要使用它(或它的一部分)时,您再次调用VirtualAlloc来提交以前保留的页面的区域。 这实际上确实很有用,但是我最终希望将我的应用程序移植到linux-因此,如果以后无法移植,我就不想使用它。linux有办法吗? 编辑-用例 我正在考虑分配4 GB或类似的虚拟地址空间