简体   繁体   English

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

[英]Why not allocate and deallocate memory frequently in C++ games?

I'm a recent convert to C++ for game programming - I have a lot of experience dealing with memory management and garbage collection woes in C#, but not as much with C++. 我最近转换为C ++用于游戏编程 - 我在处理C#中的内存管理和垃圾收集问题方面有很多经验,但对C ++没有那么多。

I've heard some vague advice in the past to avoid allocations and deallocations during gameplay (ie new and delete ) and to pre-allocate everything you might need up front. 我过去听过一些模糊的建议,以避免游戏过程中的分配和解除分配(即newdelete ),并预先分配您可能需要的所有内容。 But that's a lot more tedious and architecturally complex than just allocating and freeing game objects as needed while the game's running (enemies, particles, etc.). 但是,这比在游戏运行时(敌人,粒子等)根据需要分配和释放游戏对象要繁琐且在架构上更复杂。

I think the advice I read was referring to resource-constrained platforms - I'm aiming to develop mostly for PC, and I imagine the game state data that would be changing frequently would be on the order of a few megabytes at most. 我认为我读到的建议是指资源受限的平台 - 我的目标是主要针对PC开发,我认为经常变化的游戏状态数据最多只能达到几兆字节。 The rest are textures, sound assets, etc. that I'll be preloading. 其余的是我要预加载的纹理,声音资产等。

So my question is: in a world of PCs with gigabytes of memory, is it worth the headache to set up elaborate memory pooling, pre-allocation, and so forth for my game state data? 所以我的问题是:在拥有千兆字节内存的个人电脑世界中,为我的游戏状态数据设置精心设计的内存池,预分配等是否值得头疼? Or is this just some unquestioned "best practice" tradition that evolved when maxing out limited platforms, that is now repeated as gospel? 或者这只是一些毫无疑问的“最佳实践”传统,在最大化有限的平台时发展,现在又作为福音重复了?

If my 2 MB of game data gets fragmented and is now spread over 4MB, I can't imagine that mattering in the slightest on a PC made after 1990 - but curious to know if I'm missing something :). 如果我的2 MB游戏数据变得支离破碎并且现在已经超过4MB,我无法想象在1990年之后在PC上做出的任何事情 - 但我很想知道我是否遗漏了一些东西:)。

The main reasons to avoid calling new unless necessary in a game environment are that 除非在游戏环境中有必要,否则避免调用new主要原因是

  1. Dynamic allocation of memory really is surprisingly expensive. 内存的动态分配确实非常昂贵。
  2. Cache misses are detrimental to performance. 缓存未命中对性能有害。

Dynamic Allocation 动态分配

At my work, we develop a game-like product (virtual surgery) and most of our memory is pre-allocated and handled via factories or memory pools. 在我的工作中,我们开发了类似游戏的产品(虚拟手术),我们的大部分内存都是通过工厂或内存池预先分配和处理的。 This is done because, dynamically allocating memory takes a very long time. 这样做是因为动态分配内存需要很长时间。 The system has to deal with memory requests of many different sizes at any and all times. 系统必须在任何时候处理许多不同大小的内存请求。 This means there's a lot of work going into processes such as minimizing fragmentation. 这意味着需要进行大量工作,例如最大限度地减少碎片。 If you ask the system for memory, you'll have to wait for it to do these things. 如果你问系统内存,你将不得不等待它做这些事情。 If you pre-allocate memory, you can use factories or other block-size-specific memory managers to alleviate these concerns. 如果预先分配内存,则可以使用工厂或其他特定于块大小的内存管理器来缓解这些问题。

I can tell you from experience that a simple mistake like allocating a reasonably large std::vector from scratch every frame, instead of reusing pre-allocated memory, can drag the frame rate down into the gutter. 我可以从经验告诉你,一个简单的错误,比如每帧从头开始分配一个相当大的std::vector ,而不是重新使用预先分配的内存,可以将帧速率拖动到阴沟中。

Cache Misses 缓存未命中

Another related issue is cache coherence. 另一个相关问题是缓存一致性。 Cache misses, which force the OS to bring a new page into the cache, are also very expensive. 缓存未命中,迫使操作系统将新页面带入缓存,也非常昂贵。 If this happens often, you'll have an unplayable game. 如果经常发生这种情况,你将拥有一款无法玩的游戏。 If, however, you pre-allocate large chunks of memory, this can go a long way towards improving cache locality, which makes cache misses few and far between. 但是,如果你预先分配大块内存,这对改进缓存局部性有很大帮助,这使得缓存错过了很少。

Moral of the story 故事的道德启示

So, in short: If you don't manage your own pre-allocated memory, you can expect a lot of your computational time to be lost to waiting for the system to allocate memory or handle cache misses. 因此,简而言之:如果您不管理自己的预分配内存,则可能会因为等待系统分配内存或处理缓存未命中而导致大量计算时间丢失。

in a world of PCs with gigabytes of memory 在具有千兆字节内存的PC世界中

And only a few megabytes for your process if a sane OS is running on that PC. 如果在该PC上运行一个理智的操作系统,那么您的进程只需几兆字节。 (But that's not the primary issue here anyway.) (但这不是主要问题。)

is it worth the headache to set up elaborate memory pooling, pre-allocation, and so forth for my game state data 为我的游戏状态数据设置精心设计的内存池,预分配等是值得的

I don't dare saying that "always preallocate everything", because sometimes it's just not possible, and for less frequently used objects, it might not worth the effort, but it is certainly true that dynamic memory management in C and C++ is resource-intensive and slow. 我不敢说“总是预先分配所有东西”,因为有时它是不可能的,对于不太常用的对象,它可能不值得付出努力,但C和C ++中的动态内存管理肯定是资源 -密集而缓慢。 So if you render, for example 30 frames a second to the screen, then possibly avoid allocating and de-allocating and then re-allocating the buffer for the objects to be rendered during each frame/iteration. 因此,如果您每秒向屏幕渲染30帧,则可能避免分配和解除分配,然后在每个帧/迭代期间为要渲染的对象重新分配缓冲区。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM