Game engine Memory Manager

Started by
4 comments, last by demonkoryu 11 years, 1 month ago

In my game engine I currently use a singleton called MemoryManager (don't hate me for using singletons :) the engine only uses two) that allocates a big chunck of memory during engine initialization and then every sub-system "asks" the MemoryManager for a Allocator of some size.

So the big chunk of memory is split across all sub-systems... this prevents memory leaks since there's only a malloc/free pair.

The problem I'm facing is how to determine the amount of memory each sub-system needs because the sub-system have to provide the amount of memory they'll need when creating an Allocator.

I could stop using the allocators the way I do and have them ask the memory manager for more memory every time an object has to be created but that could lead to poor cache usage...

Any thoughts? Thanks.

Advertisement

There are a few good reasons to use memory pools, but you haven't listed any of them. The most common reasons are to enable fast teardown, to handle small object allocation since the default allocator runs in 4k blocks, and to provide faster allocation times in situations with several hundred thousand rapid allocations.

It won't solve memory leaks like you suggest --- if your program leaks memory it will eventually consume the memory pool.

It won't solve cache issues since that is based on how you use the memory, not how you allocate it.

What problem are you trying to solve? Why do you think your custom allocator will solve it?

In my game engine I currently use a singleton called MemoryManager (don't hate me for using singletons smile.png the engine only uses two) that allocates a big chunck of memory during engine initialization and then every sub-system "asks" the MemoryManager for a Allocator of some size.

So the big chunk of memory is split across all sub-systems... this prevents memory leaks since there's only a malloc/free pair.

The problem I'm facing is how to determine the amount of memory each sub-system needs because the sub-system have to provide the amount of memory they'll need when creating an Allocator.

I could stop using the allocators the way I do and have them ask the memory manager for more memory every time an object has to be created but that could lead to poor cache usage...

Any thoughts? Thanks.

You are better of giving you memory manager a settings file to deserialise at run time which defines all the sizes of the pools you need. This way you can edit it without having to recompile your code base and it also makes it easier to keep track of what each system is using, instead of having to hunt the allocator constructors in your code. And then have your systems ask for a pointer to the allocator that's appropriate for that system, this way you can also combine pools when they ain't needed, implement virtual allocators that can actually swap pools on demand.

As Frob already pointed out all of this will not fix memory leaks (these are now harder to track unless your memory manager takes care of this). Optimal cache usage won't come from a memory manager it comes more from the algorithm and data structures you use to operate on this.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

In my experience, tight memory management can be incredibly useful in certain situations, on certain platforms, and less necessary in others.

Keeping tight control of memory is particularly useful on things like consoles, devices with limited memory, and especially situations where there is no swapping to disk to page in 'extra memory' when you run out. In these situations, if you run out of memory, either your application handles it gracefully (says 'cannot do this' or whatever) or you get a crash.

Certain applications, like games and rocket control software, or plane autopilots, I see as more 'mission critical' so I don't want them to fail or crash under any circumstances. Whereas for e.g. a word processor, it is more acceptable when trying to load a document if it says 'cannot load document, not enough memory on this device' (although obviously you'd try and design to prevent this happening). But playing a game it's no good if it says 'cannot load level 5, out of memory', as you cannot progress in the game.wacko.png

So for games that are anything other than very simple ones, myself I would tend to use a memory manager. However, for general applications / editors etc which have to adapt to what particular document / documents they are editing, where they are allowed to 'fail' due to out of memory errors, I'm much more likely to just use directly or indirectly the OS allocators.smile.png

If you do preallocate blocks of memory for each of your game 'modules', you are right in saying it is useful in advance to know how much memory to allocate. Preallocating blocks for different modules can be very useful when you need to work to a memory budget, particularly with a team of programmers, rather than just putting it all together and 'hoping it doesn't run out of memory'. For some areas, this will be easy to workout (e.g max number of sound buffers, things like that).

For others, particularly game level resources, the memory requirements may change from level to level. You may want certain levels to have more sound data than others, some more texture data, etc etc. However, a way around this, rather than having set limits for sound data / textures / geometry etc, is to have these data shared in a 'level file'. And have a certain maximum size for your level file data.cool.png

For tracking memory leaks, as the others say, just because you are using your own allocator it doesn't automatically 'fix' leaks. However, you should design your allocator so that along with the allocation it can store things like the line number and filename (in some type of debug build). Then on exit, you can report any allocations unfreed after cleanup, and other statistics, like the maximum memory used in each module etc.

You can also put 'check' regions of a few bytes around allocations, to detect when you have written outside of bounds, off the end of arrays etc.ph34r.png

There are also 3rd party systems you can use for most of this leak detection and bounds checking. Although these may not be available on your target platform .. so having your own can be very useful. It's the kind of thing you can write once and reuse in other projects, and great to have in your 'toolbox'.

p.s.

(don't hate me for using singletons smile.png the engine only uses two)

Two too many.

p.s.

(don't hate me for using singletons smile.png the engine only uses two)

Two too many.

That is just dogmatism. A singleton is a tool; one to be used sparingly, sure.

This topic is closed to new replies.

Advertisement