【问题标题】:Out-of-process memory heap to work around 32-bit address space处理 32 位地址空间的进程外内存堆
【发布时间】:2013-04-08 08:17:29
【问题描述】:

问题:大型模拟游戏有大量不同的对象,必须对其进行跟踪、更新,并用于视觉渲染和逻辑模型更新。只有 4 GB 的地址空间,您只能将这么多的东西放入内存中。如果你求助于磁盘,事情就会开始变慢,除非你很幸运并且不断地访问页面缓存。但即便如此,当文件系统同步到磁盘时,进行大量更新/写入的成本也会很高。

假设用户至少有 32GB 的 RAM(少数人报告为 64GB)并且想要玩一个巨大的模拟,导致模型携带的数据比游戏开发的大多数东西多一个数量级处理。他们当然有 64 位操作系统(比如说,Windows 7 x64 或 Windows 8 x64)。自然,如果您只是将所有这些模型数据存储在进程中的虚拟地址空间中,即使使用大地址感知,您也会遇到内存不足的情况,即使主机有千兆字节和千兆字节的空闲 RAM(因为 32 位进程已用完 虚拟地址空间 (VAS))。

我们还假设,由于完全无法控制的原因,您无法将主二进制文件设为 64 位。你依赖于一些专有框架,花费了可笑的工时来编写该框架,并且必须从一开始就重新开始以转移到其他东西。你的框架只提供 32 位版本,所以你被卡住了。

对吗?

也许吧。

我有一个随机的想法,这似乎是一个很长的目标,因为我不知道我是否可以让它变得高效或实用。

如果我可以创建一个 64 位子进程,那么它就能够在所有实际用途中使用今天任何人都可以买得起并插入主板的 RAM,即使在非常高端的服务器上也是如此底盘。

现在,我希望能够有效地从模型中存储和检索大量数据,这些数据已被推入子进程,并且不时将这些数据的子部分复制到子进程中到时间。所以基本上,所有千兆字节荣耀的“主要”模型(一系列非常巨大的树型和哈希表结构)将位于 64 位进程中,而 32 位进程将在那里窥视,抓住一个大块数据,用它做一些事情(或者我应该让子进程在那里进行一些处理以将其提取出来??),然后摆脱它——以保持 32 位进程中的内存使用可管理.

所有模型读取/变异/模拟算法都基于模型在本地进程中可用的假设,因此诸如随机数组访问之类的事情很常见。对我来说,我很难将我的访问模式从主模型中提炼成几个基于块的顺序读取,而且遍历整个模型也并不罕见。

我的目标是:

  • 防止该死的东西由于内存不足而崩溃(#1 目标)
  • 性能(非常接近 #2,但使用极端复杂性的人可能会接受比模拟更小、更简单游戏的人更差的性能)
  • 对现有代码的最小重构(或多或少带有渲染调用和多线程的普通 C++)

这似乎是一个相当艰巨的项目,因为从一个连贯的内存模型到必须从一个比我任何时候都能抓住的大得多的模型上看一个孔径,这可能需要重新设计大量的算法.

我的问题:

  • 这样做有没有先例?
  • 如何最好在 Windows 上完成?是否有类似 Linux 上的某种共享内存,或者轻量级的超高带宽随机内存访问 IPC,可以通过类似 operator[]() 实现的方式集成到 C++ 中?
  • 任何 IPC 的性能是否会如此糟糕以至于不值得尝试?我是否应该只依赖磁盘(您知道,数据库或键值或其他什么)并让操作系统/文件系统弄清楚如何使用 RAM?

请记住,我需要支持非常“健谈”的 IPC 机制,因为许多处理算法(AI 等)都是围绕小内存访问和更新设计的。这在进程中运行得很好,甚至对缓存局部性有一些关注,但是当您通过 IPC 访问它时,这一切都变得很奇怪。

【问题讨论】:

  • 你为什么不把你的主程序做成 64 位?为了让他们使用您的子进程,他们无论如何都需要运行 64 位操作系统和硬件,为什么要让事情复杂化呢?现在他们有多大可能运行内存超过 4 GB 的 32 位操作系统?
  • @GabeSechan 请阅读第三段。当您遇到如此复杂的事情时,“仅将主程序设为 64 位”可能意味着切换到新引擎并放弃 人年 的工作。这对于未来的项目来说是可能的,但对于当前的项目来说却不是。
  • 1) 在批评之前,您是否尝试过使用来自 HD 的多线程核外流式传输? 2) 如果我没有 32GB 的 RAM 并且不想购买它怎么办,这是否意味着我不能成为您软件的用户?换句话说,您确定您的所有客户都愿意安装这么多内存吗?
  • 我想看看是否可以将 32 位框架移动到下属 32 位进程中,或者在 64 位进程中编译并虚拟化/模拟它。
  • “地址窗口扩展”使得在 32 位进程中使用超过 4g 的内存成为可能。它似乎只在服务器版的 windows 上可用。

标签: c++ winapi ipc out-of-memory


【解决方案1】:

如果理解正确的话。

如果您使用多个进程,则窗口仍需要将各个部分分页进出。

这就是我想尝试的方式。

使用memory mapped files 映射您需要的磁盘上保留的内存空间的视图/部分。你当然需要有一些内部映射方案。

目前我不知道的关键是您是否可以从 32 位访问 64 位 API。

Windows 会神奇而高效地处理分页。无论如何,这就是它对内存映射虚拟内存的作用。我们曾经使用它来处理早期 32 位 NT 系统上的海量数据集,并且该技术可以正常工作。

【讨论】:

  • 您的意思是“非持久内存映射文件”(该术语取自您提供的链接)?这不是基本上只是一个进程内缓冲区吗?如果进程是 32 位的,那就没有多大帮助了……
  • 我上一次在 Windows 上使用内存映射文件的旅程最终不幸地发现它在文件大小方面存在限制。例如,在映射文件超过 ~600MB 后,它开始随机崩溃。
  • @Haroogan 我预计会发生这种行为,因为您的 VAS 用完了。这只是在我原来的帖子中提出问题。数据必须永久存储在文件中(或其他地方,像另一个进程),然后在该文件的子集中有一个“孔径”以将其映射到内存中。我试图摆脱使用磁盘,因为这个模型有一个完全独立的序列化过程,而且它更新得如此频繁,以至于它在运行期间通常不会像当前设计的那样存储在磁盘上。
【解决方案2】:

我的情况和你类似,GUI 是 32 位的,但需要 x64 代码才能与系统交互。我们采用的方法是使用 WM_COPYDATA 并通过神奇的进程位边界来回传递数据。自然,它不如使用 dll 快,但这不是一个选择。对于我们的用例来说,性能折衷是可以接受的。

【讨论】:

    猜你喜欢
    • 2012-01-22
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    相关资源
    最近更新 更多