Game Design, Programming and running a one-man games business…

Memory allocation improvements

I’ve been working on about 16 different things, but one of them was to reduce the memory leakage of GSB. I know some people design very cunning survival-mode fleets and have battles that can go on for an hour or more, and basically GSB leaks memory quite badly right now. Also, if I ever want this game ported somewhere, it will need to get it’s memory use under control. Plus campaign games sometimes lead to some VERY big battle, which makes the issue worse.

Lots of fiddling around (writing my own memory allocation debug stuff) means I could watch exactly what was getting allocated mid battle. I dumped every memory allocation during battle to a text file, then chopped off the first 10,000 (so I don’t worry about early allocations, which are then cached and re-used anyway), so I could see what the long term persistant offenders were.

The next step was to ensure I was looking at the *amount* of RAM being used, not the number of small trivial 20 byte allocations. Those need optimizing too, but not now. To do this, I stuck all the text which looked like this:

file:..\src\GUI_Particles.cppline:429 28672
file:..\src\GUI_Ship.cppline:733 204
file:..\src\SIM_TargetedModule.cppline:905 48
file:..\src\SIM_TargetedModule.cppline:981 12...

Into Excel, and created a pivot table out of it, to nicely summarise each allocation type by number of calls and total RAM allocated. It was clear that particle allocations were rare, but huge. It was immediately clear that I was allocating memory for a big mega explosion even for the tiniest 7 particle fighter-impact effect. All I did was re-write the particle code to calculate on application-start what the maximum number of particles were that this emmiter could ever need, and then ensure it never allocated more than that when I created it.

Some more work with extensive debug display code mid-battle was done to ensure the new system was working as expected, and that the majority of the allocated RAM was indeed needed and being used.
End result? My test battle (Multari nebula, a fair few fighters, fought to the end with all options turned on) went from a peak of 403MB for GSB.exe to 305MB. That’s pretty darned good. The savings on bigger, longer battles will be pretty noticable.

Expect that improvement to be folded into a future update.


7 thoughts on Memory allocation improvements

  1. Thats exactly the reason why I don’t like to ever start my own program or programming on something bigger than a little script.

    With 99,9% chance there already is a better version of it in the use somewhere and I just didn’t find it.

    I just hate it.

  2. Hi Cliff – assuming you are developing in C++, you should seriously consider using something like boost smart pointers.

    http://www.boost.org/doc/libs/1_44_0/libs/smart_ptr/smart_ptr.htm

    These will guarantee your destructors are called when all references to an object are lost.

    And if you are using any third party C code, its good practice to wrap it up in a C++ class – ensuring your destructor frees any memory already malloced by the constructor (or other methods).

    Regardless of whether you are porting it to non-PC or not, your customers will be happier if you aren’t leaking memory (especially if its really bad and not recoverable once the application exits!!!)

  3. I think I found one of the worst contributors today, which was the fact that (due to some complex spaghetti code) the 50% of explosion plume effects that are placed beneath exploding ships, never got deleted, and just sat there in memory :D
    They don’t do that now… and the majority of GSBs memory usage is particle effects, so I bet that was a huge chunk of it.

  4. Visual Studio have some built-in support for catching memory leaks, and first thing I do for every project, is to enable it by adding these lines to the top of WinMain:

    // Enable windows memory leak detection (will report leaks in the Output window)
    #ifdef _DEBUG
    int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Get current flag
    flag |= _CRTDBG_LEAK_CHECK_DF; // Turn on leak-checking bit
    _CrtSetDbgFlag(flag); // Set flag to the new value

    // _CrtSetBreakAlloc(1624); // Can be manually commented back in to break at a certain allocation
    #endif

    then, whenever I forget to free something, when the program terminates, those memory blocks will be listed in the output window. The list shows the blocks size, a few bytes of its contents, and an allocation number. If I then add the function call _CrtSetBreakAlloc() to the the top of WinMain, and give it one of the allocation numbers from the memory leak list, a break-point will be triggered when I next run the game, on the specific line where the original allocation happened. Very useful to instantly find memory leaks, and I always use it to make sure I never have any :-)

    It doesn’t help when dealing with large memory use at peak times – but it helps for plain leaks.

Comments are currently closed.