为什么不在C ++游戏中经常分配和释放内存?

时间:2013-04-09 05:42:39

标签: c++ memory-management game-engine

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

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

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

所以我的问题是:在一个拥有千兆字节内存的PC世界中,为我的游戏状态数据设置精心设计的内存池,预分配等是否值得头疼?或者这只是一些毫无疑问的“最佳实践”传统,在最大化有限的平台时发展,现在又作为福音重复了?

如果我的2 MB游戏数据变得支离破碎并且现在已经超过4MB,我无法想象在1990年之后在PC上做出的任何事情 - 但我很想知道我是否遗漏了一些东西:)。

2 个答案:

答案 0 :(得分:21)

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

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

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

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

    缓存未命中

    另一个相关问题是缓存一致性。缓存未命中,迫使操作系统将新页面带入缓存,也非常昂贵。如果经常发生这种情况,你将拥有一款无法玩的游戏。但是,如果你预先分配大块内存,这对改进缓存局部性有很大帮助,这会使缓存缺失很少。

    故事的道德

    因此,简而言之:如果您不管理自己的预分配内存,那么等待系统分配内存或处理缓存未命中会导致大量计算时间丢失。

答案 1 :(得分:3)

  

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

如果在该PC上运行一个理智的操作系统,那么您的进程只需几兆字节。 (但这不是主要问题。)

  

为我的游戏状态数据设置精心设计的内存池,预分配等是值得的吗

我不敢说“总是预先分配所有东西”,因为有时候这是不可能的,对于不常用的对象,它可能不值得努力,但是动态内存管理肯定是正确的。 C和C ++是资源密集型且速度慢。因此,如果您每秒向屏幕渲染30帧,那么可能会避免分配和取消分配,然后为要渲染的对象重新分配缓冲区在每个帧/迭代期间。