do most games do a lot of dynamic memory allocation?

Started by
99 comments, last by Norman Barrows 9 years, 3 months ago

i was watching a very interesting video:

"Ideas about a new programming language for games." by Jonathan Blow, creator of Braid and The Witness...

everything he was saying rang true for about the first 18 minutes or so, until he started talking about memory management.

his point was that games do a lot of dynamic memory allocation, and a language used to program games ought to support that through various language constructs.

and that just didn't ring true for me. perhaps its the way i design games. i favor statically declared data structures of fixed sizes in the data segment as opposed to dynamic memory allocations on the heap during run time. the reason is simple, if you don't use memory pointers, you can't get memory leaks, or dereference nil pointers. so all those headaches go away. don't get me wrong, i'll allocate a 1 meg buffer on the heap to do a crc check of a file, then deallocate right away. and i just finished using explicit pointer casts of a D3DXVertexBuffer to a vertex struct pointer with indexed addressing in my new calc_scaled_rotated_bbox(some_mesh,scale,xr,yr,zr) routine.

but i use things like: target_struct target_list[MAX_TARGETS] for most things. IE i pretty much NEVER allocate or deallocate or dereference dynamic memory.

but i take it this isn't the way most games work?

what do most games do? whats dynamic and whats static? and why?

does it have something to do with limited resources on consoles? i'm PC only, so really limited resources are kind of a thing of the past for me. but i started on an 8088 w/64K ram, so i've paid my dues! <g>.

are things dynamic for the usual reasons one uses a dynamic data structure vs a static one? IE don't need to know MAX_TARGETS ahead of time, lists can be as big as available ram, that kind of stuff...

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Advertisement

Sporadic need of memory (e.g. working memory during loading and/or decoding a resource), unknown number of objects (e.g. network connections or pending packets), variable size of objects (e.g. enqueuing rendering jobs) ... all these may need to be handled. However, they all can be called "usual reasons".

For me also unknown number of objects etc.
Your question depends on what the definition of memory allocation is, I pretty much use std::vector everywhere, would this be dynamic memory allocation or not?

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Its rather hard to exclusively use the stack for everything, for example if you have even a basic kind of resource manager(especially if its loading a lot of data) it has to be able to control the lifetime of objects, even if you know the size of everything ahead of time you don't necessarily know how many of the thing you want. Anytime you're using a container class like vector even you're already working with heap memory, since vector has to be able to allocate as much space as it needs when it needs to resize.

If you talk in terms of number of objects, usually a ton of tiny objects you just create and throw away will be on the stack, a lot of things related to math in particular. Data, especially large chunks of data, are much more suitable to be stuck on the heap. I'm not sure its fair to same a game like Braid actually should be boasting that it uses a ton of dynamic memory or something, but I've watched the person you're talking about before and to be honest hes a bit of an essentric with a lot of his theories about games and programming sometimes.

In terms of AAA games and large engines you get into completely different territory, in that case the number of resources spirals to ridiculous levels really quickly so there have been a lot of novel attempts to improve CPU caching, lowering the number of allocations, etc. The problem with dynamic memory is that usually it ends up making even closely related objects be fragmented quite a bit since they'll just be pointers to some deep dark corner of RAM. Books like Game Engine Architecture list quite a few ways that engines can handle memory to make it more performant than just newing everywhere.

There are several useful allocation schemes besides pre-allocation: pool allocation, linear allocation, etc. All of these allow to dynamically allocate some memory without suffering the costs of new/delete.


Sporadic need of memory (e.g. working memory during loading and/or decoding a resource),

yes i use heap for that sort of thing too when called for- crc check of save game file is a good example.


unknown number of objects (e.g. network connections or pending packets), variable size of objects (e.g. enqueuing rendering jobs)

ah, but see, for these i'll use a static list and just declare it "big enough" for worst case scenario. it eliminates the dynamic allocation overhead, and the possibility of heap errors. i have yet to come upon a case where a dynamic list was truly required. no so for file buffers mind you, those can be too big for the stack and require heap use. but i have yet to come across a situation where i couldn't use a static vs a dynamic list type data structure. while the whiz bang benefits of dynamic memory seem cool, they come with a cost in code complexity and some performance overhead. often times, a static structure can get the job done while avoiding these issues.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


I pretty much use std::vector everywhere, would this be dynamic memory allocation or not?

from cpprefernece.com:

http://en.cppreference.com/w/cpp/container/vector

"std::vector is a sequence container that encapsulates dynamic size arrays."

note the use of the term "dynamic", so yes, a std::vector is dynamically allocated memory. technically its an array on the heap with some extra space - that gets reallocated when it runs out of extra space. and i suspect that reallocation is automatic - IE not initiated by you when its convenient and won't slow things down. You can control the amount of extra space to influence when reallocations occur, but when you have a list of current size N, and add the N+1 th element, its going to reallocate, right in the middle of adding a target, projectile, etc to the simulation.

do you use it out of habit or necessity?

is there no way for you to know that "i'll never have more than X number of things in this list", which would allow you to use a static structure of slightly larger size?

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


Its rather hard to exclusively use the stack for everything, for example if you have even a basic kind of resource manager(especially if its loading a lot of data) it has to be able to control the lifetime of objects, even if you know the size of everything ahead of time you don't necessarily know how many of the thing you want. Anytime you're using a container class like vector even you're already working with heap memory, since vector has to be able to allocate as much space as it needs when it needs to resize.

for this sort of thing, i'll use a static array of structs that is "big enough". in turn, member variables of the structs will be d3dpointers to d3d resources allocated on the heap.

some examples:

(i'll be nesting code in my reply, and code blocks don't work when i do that, so code is in blue, not a code block)

mesh database:

-----------------------------

#define maxmeshes 400
struct Zmesh
{
IDirect3DVertexBuffer9 *vb;
IDirect3DIndexBuffer9 *ib;
int numverts,numfaces;
};
// meshDB record
struct meshrec
{
char name[100];
//LPD3DXMESH mesh;
Zmesh mesh2;
};
// mesh DB
extern meshrec mesh[maxmeshes];
originally, a meshrec was a name and a d3dxmesh object pointer. i later replaced the d3dxmesh with the Zmesh struct, which contained just what i needed out of the d3dxmesh. meshes are loaded as d3dxmeshes, then their vb's, ib's, etc are copied to a Zmesh struct, and the d3dxmeshes are discarded. so they're just a handly file format (.x) for loading meshes basically.
max meshes is set to 400. caveman currently uses 321 meshes.
texture database:
---------------------------------------
#define Zmaxtextures 400
struct Ztexrec
{
char name[100];
LPDIRECT3DTEXTURE9 tex;
int w,h;
};
extern Ztexrec Ztex[Zmaxtextures];
maxtextures is 400, caveman currently uses 386 textures.
other brief examples:
-------------------------------
models database: max_models=200, caveman currently uses 171.
animations database: max_animations=200, caveman currently uses 165.
wavs database: max_wavs=300, caveman currently uses 200.
render queue: 5000 total entries max. render queue index: 400 textures by 5000 meshes per texture max. total entries is small as no single pass makes more than 5000 draw calls.


I'm not sure its fair to same a game like Braid actually should be boasting that it uses a ton of dynamic memory or something
agreed, lots of runtime allocation and dealloaction tends to be a bad thing (overhead, error prone, etc). thus my question, as it seems folks do it a lot more than i do.


I've watched the person you're talking about before and to be honest hes a bit of an essentric with a lot of his theories about games and programming sometimes
so i've heard, yet much (other than the memory stuff) rings so true...
as i said, i'm only half way though the second video, so i'll reserve my judgement call as to whether he's full of it or not until the end. but frankly at this point, i'm no longer watching it so much for the "new game language stuff" as i am for the things he mentions in relation to that, such as factorability (as opposed to re-factorabiity), the concept of friction free programming, the large number of observations about the pitfalls and short comings of conventional methods made by him and others such as Carmack, and the evolutionary nature of game software (IE the fact that games constantly evolve ad change over time due to the fact that almost none are pure clones and therefore are technically a new program that's never been done before, thus usually requiring some experimentation).


In terms of AAA games and large engines you get into completely different territory, in that case the number of resources spirals to ridiculous levels really quickly
so there, you need to load and discard resources in real time. and that means memory use. and i take it that dynamic is seen as a simpler way to make sure data structures are always "big enough"? although there's really no reason static couldn't be used, or one of the methods mentioned above by Haegarr.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

There are several useful allocation schemes besides pre-allocation: pool allocation, linear allocation, etc. All of these allow to dynamically allocate some memory without suffering the costs of new/delete.

i suppose i do something like this in a way. when i use an array of structs to implement a variable list (a list that changes), i use an "active" member variable in the structs. insertion adds at the first inactive slot. delete sets slot to inactive. searches skip inactive records. it a form of array implementation of a linked list.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

I have worked both inside games and outside games on business software, games are extremely restricted in allocations. Historically games have needed to give a lot of thought to memory management, far more than most business applications ever do. Yet games can still do "a lot" of allocations.


In all the PC-based business software I've seen, generally allocations happen all the time. Less so on carefully engineered servers, but those are becoming scarce, replaced by a bank of cheap PC servers all with sloppy code. In one project I'm working with right now, their Java code base burns through about 100MB per second and the garbage collector triggers every few seconds. It is cheaper to build the software fast and cheap then buy 10 machines at $500 each than to have the product team spend months in careful design, months in optimization, months in performance tuning, etc. They do not care about the costs of object creation and memory management, and considering their environment, they do not need to. Memory management is not a big concern.

In games, especially games on consoles or game code shared with consoles, memory management is a major issue. On game consoles you don't get virtual memory where everything is swapped to disk. You have a very small memory pool to work with, although with each generation you have a little more space. On the DS you had 4MB. PS2 had 32MB. Original XBox had 64 which you shared with the OS. PS3 has 256 and you got about half. X360 had 512 and you got about half. To manage the memory you generally pre-allocate large pools for various items. Many engines and studios had requirements that you use memory in particular ways, long-term objects allocated on the high end of memory, short-term items on the low end of memory. Pools ensure that you keep within budgets and help prevent fragmenting, pulling from different sides of memory also helps with fragmenting.

Contrast with the PC and its virtual memory. In 32-bit PC games you can use 2GB or 3GB of memory, in 64-bit games you can use far more. Unless and until you come close to exhausting your memory space you can allocate and release whatever you want when you want. Until you approach space exhaustion the OS can usually find a block large enough for whatever allocations you need.

Games are usually more rigorous when it comes to memory management because of the history in game consoles. Developers tend to prefer longer-lived objects, loading and unloading in large batches, and other rules. Even so, games generate a lot of short-lived objects.

This topic is closed to new replies.

Advertisement