In software development there are different types of bugs. C++ is a hard typed language which makes it easy for the compiler to detect errors in the code. So if there is type error (int is not a float, or int is not an int* or int&) in your code, it won’t compile. It’s is a big difference from dynamically typed language, where a variable can be a string, a number or a float etc. In for instance Python all error checking will be done at runtime.
There are however bugs the compiler won’t detect. These bugs causes your game to leak memory, run inefficient or crash (segmentation fault). I have spent numerous hours to sort these kind bugs out during the development process of spacefight.
It all bottles down to how C++ does dynamic memory allocation. You might allocate memory and never free it. You might free memory with delete and try accessing it again (crash). A rule of thumb is that you should be very careful allocating memory with new, in C++11 there has been a lot of work implementing so called smart pointers, which makes the memory a lot nicer and safer to work with.
So how to?
So if the compiler won’t catch the memory leaks or inform you about where and why your game crashed, how will you ever find out what went wrong and where? It’s here where debuggers and profiling tools come in to play.
For this project I have been using gdb. It’s a fairly cryptic debugger of which capabilities I just have scratch the surface of. But in many cases it’s been pointing me towards the right direction where to look. In most crashes the reason has been that I’ve tried to use objects in memory that has been deleted or not even created. It’s worth looking into a tutorial for gdb like this one. Gdb can be a good tool in order to figure out why your game is crashing.
The profiler runs on top of your application. It looks for calls like allocate memory, free memory. In this way it can detect where in the code the program leaks memory. I have been using Valgrind to profile the application. In some stages in the development I found out that the program had eated several megabytes of memory in a few seconds, which I luckily tracked down with Valgrind. A usual memory trap is the TTF_RenderTextSolid, this creates a new SDL_Surface every call and need to be freed when it’s been used. Especially if you “blitting” dynamic text like a score onto the screen.
// Allocates a new SDL_Surface
text = TTF_RenderText_Solid(textFont, msg.c_str(), tc);
// Blitting to screen
applySurface(73, 190+99, text, screen);
// And free the allocated surface. Important!
The profiler can do a lot more for the enthusiast. It can track down all the calls in your application and dump it into a file. After that you can use a graphical application like kcachegrind to examine it. This is very effective to analyze your game in for optimization if you have performace issues.
Keep in mind that SDL 1.2, at least under Linux will leak about 2KB, so don’t be frustrated if you cannot find leakage in your code. This is leak that is regarded as “ok” since it doesn’t increase in size and is very small. But it’s still annoying!
==3598== LEAK SUMMARY:
==3598== definitely lost: 303 bytes in 7 blocks
==3598== indirectly lost: 1,728 bytes in 38 blocks
==3598== possibly lost: 0 bytes in 0 blocks
==3598== still reachable: 94,787 bytes in 552 blocks
==3598== suppressed: 0 bytes in 0 blocks
==3598== Reachable blocks (those to which a pointer was found) are not shown.
==3598== To see them, rerun with: --leak-check=full --show-reachable=yes
Some final words of advice on this topic; What I learned through the process
- Do memory check frequently during the development, in an early stage. This will deduce the places that has memory leaks.
- For every new there’s a delete
- If your program crashes, it probably tried to access something that isn’t there.