Finding Memory Leaks of Legend of Tux

From LD Smith Games Workshop
Jump to navigation Jump to search

Here is a process I used to resovle a memory leak in The Legend of Tux. This process was done in Windows, so finding memory leaks in Linux will be somewhat different, but the overall process should be the same. For Linux, I would recommend using "ps -ef | grep <program name>" or "top" to determine how much memory your program is using (or "prstat" in Solaris).

First, start Task Manager (Ctrl-Alt-Delete => Start Task Manager)

Click the Processes tab

Start your application, and the name of your executable should show up in the list

In the screen below, I see that my program is using 13M of memory, and half the CPU

Lotux taskman001.jpg

When I go to the stage select screen, it still uses about half the CPU, but the memory used jumps to 26.5 M

Lotux taskman002.jpg

I select a stage, and the memory used again increases to 87M

Lotux taskman003.jpg

I quit the stage, return to the title screen, and select another stage, which increases the memory used to 168 M. I was able to very quickly run up the amount of memory used to 300+ M by quitting to the title screen, selecting a stage, and repeating.

Lotux taskman004.jpg

Since the memory increases occur when a new screen is loaded, I have a good clue that makes me believe that the memory leak is due to not freeing the memory used to store the music data buffer.

I checked the audio.c file that I am using to handle the SDL_Mixer commands, added "Mix_FreeMusic(music);" and "music = NULL;" code before the audio is loaded. I recompiled and tried the program again, but the memory still significantly increased between screens.

My next guess is that it is due to the SDL_Surface objects not being free'd.

I checked the main lotux.c file, and I found that there were images being created at the beginning of the gameLoop function that were not being free'd. Originally, the gameLoop function was the main function of the game, which was only called once in the program. However, the gameLoop function can now be called multiple times in the game, every time a level is selected. I moved all the image creation calls to the LoadSprite method (which is called at program startup), and I created a freeSprite method which is called before the program exits.

I tried running the program again.

Now there is a big jump to 63M memory usage when the program starts up, however this is not a bad thing. All images are now being loaded at startup, instead of being reallocated and reloaded on every time the gameLoop is called.

Lotux taskman005.jpg

When I go to the main game screen, the usage rises to 83M, which is nearly the same before I made any changes. This is expected, since I am loading all images at the start and free'ing them just before the program exits. If I wanted, I could free the images for the title screen and stage select screen before moving to the main game loop. However, the extra processing and load required to do that dynamically probably isn't worth the small amount of memory I would save from it. However if I needed to get the program to run smoothly on an old system (with maybe less than 256M of RAM), I would need to unload the title screen and stage select images, and reload them when those are needed.

Lotux taskman006.jpg

After exiting to the title screen, and returning to the game screen the amount of memory used only increased to 102M. Repeating this process results in the amount of memory being used increasing by 16M each iteration (title screen => stage select => game loop). Before I made the changes, I was seeing an increase of 81M (168 - 87) for each iteration. So there is still a problem, but the jump in amount of memory usage is not quite as huge. A further investigation will need to be pursued to determine any remaining memory leak problems. The arrays used to store the collision and title data for all the maps is a possible source of the remaining memory leak.

Lotux taskman006.jpg

Looking into it some more, I noticed that 10M was being consumed every time the level select screen loaded. I created "selectLoadImages" and "selectFreeImages" methods that were called upon start and exit of the level select screen. The "selectFreeImages" called SDL_FreeSurface on all of the images created for the select screen. However, the amount of memory used still increased by approximately 10M every time the stage select screen displayed. Maybe this is a problem from the SDL library itself. Or maybe it just doesn't deallocate the memory when SDL_FreeSurface is called, unless there is a need for that memory elsewhere... who knows? Anyway, I moved the calls to "selectLoadImages" and "selectFreeImages" to the beginning and end of the entire program, so those methods are only called once. After the changes were made, I tested again and the 10M memory leak on the title screen was reduced to 12K (76,912K - 76,924K). That made a huge difference. There still appears to be an additional 5M allocated every time the gameLoop is executed, and an additional 5M allocated when quitting from the gameLoop to the title screen.

The culprit is found!

Today, I was looking at my image creation method, and I noticed the following:

 img = SDL_DisplayFormat(img);

This made me wonder if the original memory allocated for the image was discarded (dangling pointer?), and the SDL_DisplayFormat method returned a newly allocated image. So I created a new SDL_Surface called "imgReturn", and changed the line above to return imgReturn, and I free'd the original img.

 imgReturn = SDL_DisplayFormat(img);

I ran the program again, and there was no more memory increases between screens! At least it was negligable (less than 1 MB). Additionally, the program now runs with half the amount of memory (around 54 MB).

Lotux taskman008.jpg