我最近转换为C ++用于游戏编程 - 我在处理C#中的内存管理和垃圾收集问题方面有很多经验,但对C ++没有那么多。
我过去听过一些模糊的建议,以避免游戏过程中的分配和解除分配(即new
和delete
)并预先分配您可能需要的所有内容。但是,这比在游戏运行时(敌人,粒子等)根据需要分配和释放游戏对象要繁琐且架构复杂得多。
我认为我读到的建议是指资源受限的平台 - 我的目标是主要针对PC进行开发,我认为经常变化的游戏状态数据最多只能达到几兆字节。 。其余的是我要预加载的纹理,声音资产等。
所以我的问题是:在一个拥有千兆字节内存的PC世界中,为我的游戏状态数据设置精心设计的内存池,预分配等是否值得头疼?或者这只是一些毫无疑问的“最佳实践”传统,在最大化有限的平台时发展,现在又作为福音重复了?
如果我的2 MB游戏数据变得支离破碎并且现在已经超过4MB,我无法想象在1990年之后在PC上做出的任何事情 - 但我很想知道我是否遗漏了一些东西:)。
答案 0 :(得分:21)
除非在游戏环境中有必要,否则避免调用new
的主要原因是
动态分配
在我的工作中,我们开发了类似游戏的产品(虚拟手术),我们的大部分内存都是通过工厂或内存池预先分配和处理的。这样做是因为动态分配内存需要很长时间。系统必须在任何时候处理许多不同大小的内存请求。这意味着需要进行大量工作,例如最大限度地减少碎片。如果你问系统内存,你将不得不等待它做这些事情。如果预先分配内存,则可以使用工厂或其他特定于块大小的内存管理器来缓解这些问题。
我可以从经验告诉你,一个简单的错误,比如每帧从头开始分配一个相当大的std::vector
,而不是重新使用预先分配的内存,可以将帧速率拖到阴沟中。
缓存未命中
另一个相关问题是缓存一致性。缓存未命中,迫使操作系统将新页面带入缓存,也非常昂贵。如果经常发生这种情况,你将拥有一款无法玩的游戏。但是,如果你预先分配大块内存,这对改进缓存局部性有很大帮助,这会使缓存缺失很少。
故事的道德
因此,简而言之:如果您不管理自己的预分配内存,那么等待系统分配内存或处理缓存未命中会导致大量计算时间丢失。
答案 1 :(得分:3)
在具有千兆字节内存的PC世界中
如果在该PC上运行一个理智的操作系统,那么您的进程只需几兆字节。 (但这不是主要问题。)
为我的游戏状态数据设置精心设计的内存池,预分配等是值得的吗
我不敢说“总是预先分配所有东西”,因为有时候这是不可能的,对于不常用的对象,它可能不值得努力,但是动态内存管理肯定是正确的。 C和C ++是资源密集型且速度慢。因此,如果您每秒向屏幕渲染30帧,那么可能会避免分配和取消分配,然后为要渲染的对象重新分配缓冲区在每个帧/迭代期间。