do most games do a lot of dynamic memory allocation?

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


And wasn't it you who not long ago had to make a chance which required searching all over his code base to do because the thing you were changing was accessed from so many places?

yep, 99 code changes.

i'd have to check and see if that was due to an API change. its unlikely it was due to use of globals. i honestly have few or no problems working with globlas, perhaps because i'm used to their issues, and therefore don't do crazy things with them.

just checked it, the 99 changes was a new member variable added to both players and and NPC entities. it impacted almost every aspect of player and entity related code in the game. use of generic iterators would have reduced this. i added them when i made the changes.


but at the same time don't pretend it is in any way, shape, or form 'good practise' to do things your way because it simply isn't.

i don't claim it is. all i can say is that so far it has worked for me for my projects.

but again, this is not about how i do things, my question is about how other people do things, because what i was hearing (lots of allocations) was weird.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Advertisement

I think a lot of the confusion is stemming from the fact that the advocates of the static approach are creating strawman arguments and suggesting that any approach using the heap must be making frequent allocations every frame. This is clearly not the case. Almost all of us would look at pool allocators from preallocated chunks of memory for small objects that are going to be created and destroyed frequently. The point is that if my pool runs out of memory during use, I can increase its size (or, better, design it so I can add a new chunk of memory without affecting the existing chunks) which might have a performance penalty for that particular frame but then all continues as it was.

Taking away these strawman attacks, I can see absolutely no advantage to statically allocated memory. The idea that there is some kind of horrendous complexity associated with managing dynamic memory just suggests to me that people are writing C with classes and haven't embraced any of the "modern" (that term is stretched a little here) techniques that we use to manage it. That was certainly my impression from John Blow's video, where he presented the:


struct x
{
    Vec3 *p;
    int count;
};

pattern as an example of something that occurs frequently in professional production code. It is also my impression from the bits of the Caveman source I've seen, which is perfectly cool if it works for you, no problem. But it isn't "good" design.

Of course this approach works fine if you are happy to limit your resources to a predetermined amount. But to model it with dynamic heap allocation has, as far as I am concerned, absolutely negligable cost in terms of complexity and absolutely no cost in terms of performance, and removes all these completely unnecessary hard limits.

Yes, okay, every time you allocate memory, you have a "potential fail point". But so what? There are two possibilities here:

a) Your program can just exit when it runs out of memory. You catch std::bad_alloc at the top level of your program and show a dialog saying the machine does not have enough memory to run this game. This is not made easier by trying to allocate all the memory at startup.

b) Your program is controlling a nuclear power plant and must keep going no matter what. You have a system in place to free up other memory in std::set_new_handler or whatever, you have to track memory allocation very carefully and you need to deal with this. This is not made easier by trying to allocate all the memory at startup.


advocates of the static approach

i don't advocate any particular approach (except dynamic when size needs to be variable - obviously). i simply use static out of habit more than anything.

i was wondering what approaches other people use, because what i was hearing didn't seem right.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


the only real benefit is it saves me a malloc at program start and a free at program end, and perhaps one machine instruction during access.

It doesn't save you a malloc/free at all -- It saves you having to write them in your source code, but the program loader still performs that allocation on your behalf. As I said, it probably coalesces all uninitialized data into a single system allocation, but you could do that too.

It also doesn't save you a machine instruction -- at compile time its not known what static address the memory will be located at, so you get a 'handle' to your data segment entities by their address, just as you would any other allocation, when the program is loaded -- The program loader won't go through the entire program to patch all your accesses with address literals. And as phantom says, that might even be worse than if those addresses were found in a more local scope due to cache locality -- but even still, even if there were an additional instruction to cost you something, the reality of modern hardware is that many instructions are effectively free because of instruction-reordering/super-scalar execution, and that the instruction windows are plenty big enough to make an optimal decision in this use case.

As I said, if its working for you, great, we're no one to argue that you should change; but again, I think we're trying to make it clear that you aren't gaining all that you think you are. It saves you having to type malloc and free somewhere -- that's it. What it costs you in terms of flexibility and in terms of logical structure has been pretty well addressed previously in this thread. I don't personally make the same tradeoff you are, even in small projects, but that's my mileage.

throw table_exception("(? ???)? ? ???");


The idea that there is some kind of horrendous complexity associated with managing dynamic memory just suggests to me that people are writing C with classes and haven't embraced any of the "modern" (that term is stretched a little here) techniques that we use to manage it.

That's funny. You really need to start watching Handmade Hero to challenge your opinions on this stuff! Casey talks a lot about people with your kind of mindset.
For what it's worth: in my experience reading blog posts and listening to talks by experienced programmers (i.e. engine programmers at naughty dog, insomniac, ubisoft, etc.) the topics are usually about data-oriented design, cache efficiency, dislike of C++/STL and its implementation, absolutely no exceptions, a _very strong_ hate against OOP and "modern design". Engine programmers seem to prefer old school approaches: plain C language, plain data structs and functions, circular and fixed-size arrays for everything.
Now, granted, this is low-level engine programmers we are talking about where performance is more important than supposedly "good design". Also they have far more platforms and hardware limitations to think about than any other programmer dealing mostly with PC.
I guess the crux of this debate comes down to the definition of "most games". Are we talking exclusively AAA? AAA + professional / full time indies? Hobby games by experienced individuals? Every little game made by everyone, regardless of experience?

The answer to "do most games do a lot of dynamic memory allocation" can probably summed up like so:

Professional teams almost certainly take great pains to avoid dynamic allocation during gameplay, but do not shy away from it during explicit loading times. Generic engines probably must do dynamic allocations to remain flexible for the wide variety of games they are used for, but heavily game specific code (like Norman's) can make certain assumptions to avoid that.

Other than that, it comes down to what is acceptable in your frame budget. Simple games like Asteroids could probably allocate for every game entity created without a problem. I'd argue that it would be over-engineering to bother with techniques like memory pools for a game like that.

I guess a slightly more interesting question might be: "is language support for dynamic memory ownership necessary in a language aimed at professional game programmers".

For what it's worth: in my experience reading blog posts and listening to talks by experienced programmers (i.e. engine programmers at naughty dog, insomniac, ubisoft, etc.) the topics are usually about data-oriented design, cache efficiency, dislike of C++/STL and its implementation, absolutely no exceptions, a _very strong_ hate against OOP and "modern design". Engine programmers seem to prefer old school approaches: plain C language, plain data structs and functions, circular and fixed-size arrays for everything.


You should qualify that with 'some engine programmers' and even then these things come with qualifiers.

For example C++ is fine, no one really has a problem with it as a core, what people dislike is things covered in 'typical C++ bullshit' type talks which go directly against data orientated design considerations - but the language itself is no more disliked than any other language out there.

The Standard Template Library tends to be a love/hate thing - the ideas are sound but lack of memory control is a problem (which on consoles is a real consideration), and the code is general which might not have the performance of hand tuned stuff. ('might' being the keyword; some years past now someone here benchmarked the Vs.Net 2002 Std containers vs Quake3's handrolled ones and found they were much faster). That also tends to be legacy due to existing code bases - some places are considering switching for some things now. There is also a deep distrust of template code which may or may not be 100% justified again depending on the situation.

Exceptions are a two fold thing; historical because of poor implementations and overhead (certainly on older systems) and simply a case of 'not needed' because games tend not to run into real exceptional cases which aren't already allowed for in the code flow. Largely a performance thing because the same people can/will use exceptions in code.

The hate for 'OOP' isn't about OOP but about the 'classes for everything!' over engineered Java trained bullshit which is spat out by graduates these days; OOP in the right place and with the right considerations is fine but it's knowing the right time and place to do things. A Vector might be an object and you are still dealing with it as an object but that doesn't mean you forget everything else. This is more an anti-bullshit sentiment than an anti-OOP (and C can do OOP just as much as C++, you just have to hand roll things).

"Modern design" is also gaining traction because a lot of 'modern design' is simply common sense; things like smart pointers have existed in engine code bases for a long time already so much of this isn't new. The difference tends to be handed rolled things and a lack of fear about using raw pointers when it is the correct time to do so. Even containers are common, just tend to be handed rolled.

You'll find plenty of engine devs who use C++, and are even using C++11 features (auto, lambdas, move operators to name 3) as the compilers support them and those people will also use POD structures, free functions when it makes sense (both globally and in namespaces), fixed sized arrays for the right thing and circular buffers when it is correct.

The truly great engine programmers do not tie themselves to old dogma, they continue to evolve and improve their knowledge and their methods, learning from mistakes and improving their practises as data suggests they should.

I speak from experience as an engine programmer on AAA games.

dislike of C++/STL and its implementation, absolutely no exceptions, a _very strong_ hate against OOP and "modern design

Fallacious appeals to authority aside, do these really sound like objective reasons to you?

Bear in mind engine programmers are the most experienced because they have been in the game a long time, so are likely to have learned their trade a long time ago. Such people can be resistant to change, then they make a video expressing their opinion and everyone runs round saying "My God, the guy that worked on X said it, it must be true".

Done correctly, code employing the "modern" or "OO" paradigms these guys are claiming to be bad, or a good implementation of the STL will map to pretty much identical machine code as the "do it yourself" approach when run through a good compiler.

Data orientation has to do with how you lay your data out in memory. It has nothing to do with the higher level language constructs you use.


...

Thank you! It's nice to read a different perspective on that stuff. Also I'm glad that what's taught in CS classes is not all garbage as one might think reading too much into those certain individuals.

I think Aardvajk hits the nail on the head here -- there's a dissonance between what you guys are arguing about. The original post was about dynamic memory allocation being bad for performance, and he's right. The responses are talking about various benefits of dynamic memory over static memory, and they're right too.

Most games (despite what Casey Muratori, much as I respect the man, says) do not allocate all over the place during a frame. That's the important part. There's little overhead in actually using dynamic memory, so it's not a performance issue unless you're actively allocating during a frame. Allocating a big chunk of memory to use as a scratch stack and then using it frame-per-frame is going to get you all of the benefits of just statically allocating a stack, and a lot more to boot.

This topic is closed to new replies.

Advertisement