15

我最近转换为 C++ 进行游戏编程 - 我在处理 C# 中的内存管理和垃圾收集问题方面有很多经验,但在 C++ 方面没有那么多经验。

我过去听过一些含糊的建议,以避免在游戏过程中进行分配和释放(即newdelete),并预先分配您可能需要的所有内容。但这比在游戏运行时根据需要分配和释放游戏对象(敌人、粒子等)要乏味且架构复杂得多。

我认为我读到的建议是指资源受限的平台——我的目标是主要为 PC 开发,我想经常变化的游戏状态数据最多只有几兆字节。其余的是我将要预加载的纹理、声音资源等。

所以我的问题是:在拥有千兆字节内存的 PC 世界中,为我的游戏状态数据设置精细的内存池、预分配等是否值得头疼?或者这只是一些毫无疑问的“最佳实践”传统,在最大限度地利用有限平台时演变而来,现在被重复为福音?

如果我的 2 MB 游戏数据碎片化并且现在分布在 4MB 上,我无法想象这对 1990 年之后制造的 PC 有丝毫影响——但我很想知道我是否遗漏了什么:)。

4

2 回答 2

22

new除非在游戏环境中必要,否则避免调用的主要原因是

  1. 内存的动态分配确实非常昂贵。
  2. 缓存未命中对性能不利。

动态分配

在我的工作中,我们开发了一个类似游戏的产品(虚拟手术),我们的大部分内存都是通过工厂或内存池预先分配和处理的。这样做是因为动态分配内存需要很长时间。系统必须随时处理许多不同大小的内存请求。这意味着在流程中需要做很多工作,例如尽量减少碎片。如果您向系统请求内存,您将不得不等待它执行这些操作。如果您预先分配内存,您可以使用工厂或其他特定于块大小的内存管理器来缓解这些问题。

我可以根据经验告诉你,一个简单的错误,比如std::vector从头开始为每帧分配一个相当大的内存,而不是重用预先分配的内存,就会把帧速率拖到阴沟里。

缓存未命中

另一个相关问题是缓存一致性。缓存未命中(强制操作系统将新页面带入缓存)也非常昂贵。如果这种情况经常发生,您将拥有无法玩的游戏。但是,如果您预先分配大块内存,这可以大大改善缓存局部性,从而使缓存未命中率降低。

故事的道德启示

因此,简而言之:如果您不管理自己的预分配内存,您可能会浪费大量计算时间来等待系统分配内存或处理缓存未命中。

于 2013-04-09T06:00:05.450 回答
3

在拥有千兆字节内存的 PC 世界中

如果那台 PC 上运行的是健全的操作系统,那么您的进程只有几兆字节。(但这不是这里的主要问题。)

为我的游戏状态数据设置精细的内存池、预分配等是否值得头疼

我不敢说“总是预先分配所有东西”,因为有时这是不可能的,而且对于不经常使用的对象,这可能不值得付出努力,但C 和 C++ 中的动态内存管理确实是资源-密集而缓慢。因此,如果您渲染,例如每秒 30 帧到屏幕上,则可能避免分配和取消分配,然后为每个帧/迭代期间要渲染的对象重新分配缓冲区。

于 2013-04-09T05:46:29.203 回答