1

我的团队开发了一个在嵌入式 Linux 上运行的基于 C++ 的复杂多进程系统。由于没有交换分区,逐渐增长的内存泄漏可能会造成很大的麻烦。(为了便于讨论,我们假设系统中分配的所有内存都填充了非零数据。)

现在,正如这里(简洁地)回答的那样,当操作系统用完 RAM 并且没有交换时,它会丢弃干净的页面。据我了解,在这种情况下唯一的“干净”页面是那些包含 const 数据和当前/最近从 Linux 环境执行的代码,特别是我们的可执行文件和共享库,它们可能会被无害地丢弃,然后根据需要从文件系统重新加载.

起初,最近最少使用的页面会最先被删除,因此几乎不会注意到这一点,但随着分配的内存越来越多,回旋余地的数量减少,需要的代码更频繁地被换出然后再重新进入。系统开始无声无息地颠簸,但我们看到的唯一迹象是系统变得更慢且响应更慢,直到最终内核的 oom-killer 介入并完成它的事情。

这种情况不一定需要发生内存泄漏;这可能只是因为我们软件的自然内存需求超过了可用 RAM。这种情况更难捕捉,因为系统不会崩溃,并且由抖动引起的性能损失并不总是立即引起注意,并且可能与导致性能不佳的其他原因(例如效率低下的算法)相混淆。

我正在寻找一种在性能开始受到影响之前明确地捕捉和标记这个问题的方法;理想情况下,我想监视发生的干净页面丢弃的数量,希望不需要专门重建的内核。然后我可以建立一些阈值,超过这个阈值就会引发错误。当然,任何更好的想法也会受到赞赏。

我尝试了其他解决方案,例如使用 监控进程内存使用情况top,或者使用 让进程自我监管,mallinfo(3)但这仍然不能捕捉所有情况或清楚地回答总体内存使用状态的问题。我看过的另一件事是输出中的“免费”列,free但无论是否发生颠簸,它都会显示一个低值。

4

2 回答 2

2

Alex 的回答通过提到 page faults 为我指明了正确的方向,但更具体的答案是major page faults。从perf_event_open(2) 手册页

 PERF_COUNT_SW_PAGE_FAULTS_MAJ

这会计算主要页面错误的数量。这些需要磁盘 I/O 来处理。

因此,虽然这些不是我要求的干净页面丢弃,但它们是它们的必然结果 - 它们表明以前换出的东西何时从 disk换回。在无交换系统中,唯一可以从磁盘换入的是干净页面。在我的测试中,我发现这些故障通常很少而且相距甚远,但是当内存不足时会突然出现峰值(在我的系统上,连续 5 秒以上每秒出现 3 个或更多故障),并且此指示与系统变得更慢,响应更慢。

至于实际查询此统计信息,已在Measure page faults from ac program中对此进行了回答,但我建议从perf_event_open(2)手册页底部的代码示例开始(请参阅上面的链接)进行此更改:

pe.type = PERF_TYPE_SOFTWARE;
pe.config = PERF_COUNT_SW_PAGE_FAULTS_MAJ;

假设您想要获得系统范围的统计信息,而不仅仅是与当前进程有关,请将实际打开的行更改为:

fd = perf_event_open(&pe, -1, cpu, -1, 0);

这里的cpu论点很棘手。在单核单 CPU 系统上,只需将其设置为 0。否则,您将必须为每个内核打开一个单独的性能计数器(带有单独的 fd),全部读取并总结它们的结果。有关解释原因的线程,请参见此处使用get_nprocs(3)最容易获得核心数量。

于 2018-02-04T12:19:19.090 回答
1

我认为您正在寻找的指标是页面错误。作为一个绝对值,它不能告诉你任何事情,因为页面错误是系统操作的正常部分,但作为一个相对值,它可能是有用的:如果你绘制程序在不同内存使用级别产生的页面错误的数量,我敢打赌,当您的程序超过可用 RAM 并开始这个干净的页面丢弃和加载行为时,将会有一个显着的跳跃。

于 2018-01-31T09:45:48.290 回答