【问题标题】:Dumping buffered data when memory limit is near接近内存限制时转储缓冲数据
【发布时间】:2011-03-08 21:30:39
【问题描述】:

我的应用程序在后台为可能的请求缓冲数据。目前,我根据命令行参数限制缓冲区的大小,并在达到此限制时开始转储较少使用的数据。这并不理想,因为它依赖于用户指定性能关键参数。有没有更好的方法来处理这个?有没有办法在系统开始崩溃之前自动监控系统内存使用并转储最旧/最近最少使用的数据?

这里的一个复杂因素是我的应用程序在 Linux、OSX 和 Windows 上运行。但我会采取一种好方法,只在一个平台上做到这一点。

【问题讨论】:

  • 当你说“为可能的请求缓冲数据”时,你的意思是它推测性地抓取和缓存尚未请求的内容,并且可能不是(即“预取”)?
  • @AndrewJanke:是的,预取。数据集从 1MB 到几 GB 不等,分布在各种数据库和 NFS 挂载中。

标签: c++ windows linux macos memory-management


【解决方案1】:

您最好的选择可能是监控您的应用程序工作集/驻留集大小,并在分配后它没有增长时尝试做出反应。关于寻找什么的一些指示:

  • Windows:GetProcessMemoryInfo
  • Linux:/proc/self/statm
  • OS X:task_info()

Windows 还具有 GlobalMemoryStatusEx,它为您提供了一个不错的可用物理内存数据。

【讨论】:

  • 谢谢,我想这就是我要找的。​​span>
【解决方案2】:

我喜欢您当前的解决方案。让用户决定是好的。不是每个人都希望缓冲区尽可能大,是吗?如果你确实投资了某种内存监视器来自动调整缓冲区/缓存大小,至少让用户在用户设置限制和自动/动态限制之间进行选择。

【讨论】:

  • 谢谢,这是让用户选择自动或用户设置限制的好建议。
【解决方案3】:

我知道这不是一个直接的答案,但我会说退一步,也许不要这样做。

即使您拥有查看当前物理内存使用情况的 API,也不足以选择理想的缓存大小。这将取决于程序和机器(以及运行该程序的所有客户端的整体系统 + 他们正在查询的服务器)的典型和未来工作负载、平台的缓存行为、是否应该调整系统吞吐量或延迟等。在内存紧张的情况下,您将与其他机会性缓存(包括操作系统的磁盘缓存)竞争内存。一方面,您想对他们施加一些压力,以迫使其他低价值数据。另一方面,如果您在内存充足的情况下变得贪婪,您将影响其他自适应缓存的行为。

对于推测性缓存/预取,LRU 值函数很奇怪:您将(希望)首先获取最有可能被调用的数据,然后再获取不太可能的数据,因此预取中的 LRU 数据缓存可能不如旧数据有价值。通过人为地“加热”不常用的数据,这可能会导致系统范围的缓存集出现异常行为。

您的程序似乎不太可能做出比简单的固定大小更好的缓存大小选择,可能会根据机器上整体物理内存的大小进行缩放。而且它几乎不可能击败了解机器典型工作负载及其性能目标的系统管理员。

使用自适应缓存大小策略意味着您的程序的资源使用将是可变的和不可预测的。 (关于内存以及用于填充预取缓存的 I/O 和服务器请求。)对于很多服务器情况,这并不好。 (特别是在 HPC 或 DB 服务器中,这听起来可能适用于高利用率/高吞吐量环境。)一致性、可配置性和可用性通常比最大资源利用率更重要。并且引用的局部性往往会迅速下降,因此随着缓存大小的增加,您可能会获得非常递减的收益。如果这将在服务器端使用,至少保留显式控制缓存大小的选项,并且可能将其设为默认选项(如果不是唯一选项)。

【讨论】:

  • 由于您提到的许多原因,我们最终使用了固定但可配置的缓存大小。 SSD 价格的下降减轻了使内存缓存完全正确的压力。在许多情况下,磁盘变得“足够好”了。
【解决方案4】:

有一种方法:称为虚拟内存(vm)。列出的所有三个操作系统都将使用虚拟内存 (vm),除非没有硬件支持(在嵌入式系统中可能是这样)。所以我会假设存在 vm 支持。

这是 Varnish 项目的架构说明中的一段引述:

真正简短的答案是计算机不再有两种存储。

我建议你在这里阅读全文:http://www.varnish-cache.org/trac/wiki/ArchitectNotes

这是一本好书,我相信会回答你的问题。

【讨论】:

  • 这篇文章似乎暗示这些决定最好留给内核;听起来不错……但在这种情况下,Penn 的程序是否应该不限制它在(虚拟)内存中保留多少缓冲区?如果是这样,他的程序最终不会耗尽系统的所有交换空间吗?或者如果不是,他的程序如何决定何时丢弃数据,以限制他的程序的内存占用?
  • 有趣的文章。我和@Jeremy Friesner 有类似的担忧。此外,这种方法假设我要缓冲的数据是本地的,因为它依赖于操作系统内存管理器中内置的磁盘缓存。我不能假设数据是本地的。我的缓冲区使用启发式方法根据用户现在的要求来预测用户接下来要要求的内容。然后它从存储(可能存在于任何地方)请求数据并缓冲它。将此缓冲数据显式写入磁盘以“本地化”它是我们无法采用的路径,因为我们不一定对本地存储具有写入权限。
  • @Jeremy Friesner 我无法真正评论程序何时应该通过数据。这不应该是基于程序目的的算法决策吗?如果期望程序将无限期地无限增长,那么您的担忧都是合理的,但这可以说是一个完全不同的问题。 :)
  • @Penn Taylor 我不同意你假设你想要缓冲的数据是本地的。从我的角度来看,缓冲区是本地的,数据的来源与 VM 无关。我相信我误解了您的问题,但我希望这篇文章仍然具有启发性。
【解决方案5】:

您可以尝试分配一些较大的内存块,然后检查内存分配异常。如果发生异常,转储数据。问题是,这仅在达到所有系统内存(或进程限制)时才有效。这意味着您的应用程序可能会开始交换。

try {
  char *buf = new char[10 * 1024 * 1024]; // 10 megabytes
  free(buf);
} catch (const std::bad_alloc &) {
  // Memory allocation failed - clean up old buffers
}

这种方法的问题是:

  1. 系统内存不足可能很危险,并导致随机应用程序关闭
  2. 更好的内存管理可能是更好的解决方案。如果有数据可以释放,为什么还没有释放?您是否可以运行定期进程来清理不需要的数据?

【讨论】:

  • 这将告诉您何时用尽了地址空间,而不是何时开始破坏页面文件。
  • 是的,我在回答中说过“问题是,这仅在达到所有系统内存(或进程限制)时才有效。这意味着您的应用程序可能会开始交换。”我说“可能”是因为可以在没有页面文件的情况下配置系统。
  • 只要进程有剩余的地址空间,大多数 Linux 配置将允许继续分配。它正在写入分配的内存,导致实际 RAM 的分配。查找内存过量使用:mjmwired.net/kernel/Documentation/vm/overcommit-accounting
猜你喜欢
  • 2011-09-22
  • 2013-01-02
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
  • 1970-01-01
  • 2010-09-26
  • 2011-06-15
  • 1970-01-01
相关资源
最近更新 更多