进程外内存堆围绕32位地址空间工作

Out-of-process memory heap to work around 32-bit address space

本文关键字:32位 地址空间 工作 内存 进程      更新时间:2023-10-16

问题:大型模拟游戏有大量不同的对象需要追踪、更新,并用于视觉渲染和逻辑模型更新。只有4 GB的地址空间,您只能在内存中放入这么多东西。如果您使用磁盘,速度就会开始变慢,除非您足够幸运,并且不断地访问页面缓存。但是,即使这样,当文件系统同步到磁盘时,进行大量的更新/写入将是昂贵的。

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

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

对吧?

我有一个随机的想法,这似乎是一个很渺茫的机会,因为我不知道我是否能使它有效或实用。

如果我能创建一个子64位进程,它将能够使用,所有实际用途,尽可能多的内存,今天任何人都可以购买和插槽到主板,甚至在一个非常高端的服务器机箱。

现在,我希望能够有效地存储和检索已经推入子进程的模型中的大块数据,并不时地将该数据的子部分复制到子进程中。所以基本上,"主"模型的所有千兆字节的辉煌(一系列非常巨大的树状和哈希表状结构)将位于64位进程中,32位进程将在那里窥探,抓取大块数据,对它做一些事情(或者我应该让子进程在那里做一些处理以提取它?? ?),然后删除它-保持32位进程的内存使用可管理。

所有的模型读取/修改/模拟算法都是基于模型在进程中本地可用的假设,所以像随机数组访问这样的事情是常见的。我很难将我的访问模式从主模型中提取到几个基于块的顺序读取,并且遍历整个模型也不是非常罕见。

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

这似乎是一个相当沉重的项目,因为从一个连贯的内存模型到一个比我每次都能抓取的大得多的模型,这可能需要大量的算法重新设计。

我的问题:

  • 有这样做的先例吗?
  • 如何在Windows上最好地完成?是否有某种像Linux上的共享内存,或者轻量级的非常高带宽的随机内存访问IPC,可以通过operator[]()实现之类的东西集成到c++中?
  • 是否有IPC的性能差到不值得尝试?我是否应该仅仅依赖磁盘(数据库或键值或其他),而让操作系统/文件系统自行决定如何使用RAM?
请记住,我需要支持一个非常"聊天"的IPC机制,因为许多处理算法(AI等)都是围绕小内存访问和更新设计的。这在进程内工作得很好,甚至对缓存局部性也有一些关注,但是当您通过IPC访问它时,所有这些都变得很奇怪。

我的情况与您类似,GUI是32位的,但需要x64代码来与系统交互。我们采用的方法是使用WM_COPYDATA并在神奇的进程位边界上来回传递数据。当然,它没有使用dll那么快,但这不是一种选择。对于我们的用例来说,性能折衷是可以接受的。

如果我没理解错的话

如果您使用多个进程,那么窗口仍然需要将这些部分分页进和分页出。

这是我设想的尝试方式。

使用内存映射文件来映射您需要的磁盘上持久化的内存空间的视图/部分。当然,您需要有一些内部映射方案到。

我现在不知道的关键是你是否可以从32位访问64位API。

Windows将神奇而高效地处理分页。这就是它对内存映射虚拟内存所做的。我们曾经在早期的32位NT系统上使用它来处理大量数据集,并且该技术非常有效。