Zalo DS Blog

Monday, November 24, 2008

Memory Leaks

When I finished Rokoban I realized that I didn't have anything to tell me how well or bad I was working with my memory resources. So, here I'll tell you what I did to have a little bit more of control.

First of all. What's a memory leak? Well, this

void MemoryLeaker()
{
int *leak = new int[99999999];
}


is a memory leak :D

When you start learning how to make programs in C++ you soon realize that memory leaks are the more annoying part. They always teach you the basic rule: "Everything that has a new must have a delete" (or is that from the Matrix movies?). That seems easy at first, but after years of C++ development I know that no matter how hard I try, I am going to create memory leaks, and you too :P Even if you try to avoid them using smart pointers you are never safe from them.

So, is there a way to avoid them? Yeah. There are a lot of ways. You can even create a garbage collector like Java. But there is a more interesting way. It is posible not to avoid them but to let our program tell us about them. And that way you can debug your application in debug mode and finally release it without any of this checks, making it as efficient and fast as posible.

So, what is the basic idea? C++ allows you to overload new and delete. You can overload them for a class or for the whole program. And this has a lot of advantages. You can reduce memory fragmentation and you can have control of what happens any time you request some memory from the heap and when you release it. So, basically you can implement a mechanism that everytime you reserve some memory it creates an entry on a table (for example) and everytime you realease it it deletes that entry from that table. At the end of your program all the entries in your table means memory leaks.

If you really want to know more about this take a look at this link http://entland.homelinux.com/blog/2008/08/19/practical-efficient-memory-management/. I was about to write my own memory manager for my engine. But I found that Visual C implements something very interesting for you. In fact, it all began with this link http://www.highprogrammer.com/alan/windev/visualstudio.html I really recommend its reading. Here I discovered that there is already an implemented debug heap I could use instead of writing my own. It is enought for me at the moment. I can only check memory leaks on my Windows release but because I usually develop everything in Windows and then recompile it using ZEngine for the rest of the platforms I can now be sure that the common part is memory leak free. There can be still problems with all the especific parts coded for each platform but I hardly make any memory allocation there.

I am finally doing what I found in this url http://www.cplusplus.com/forum/general/3526/:

This should go into every .cpp , after all header inclusions

#ifdef _WIN32
#ifdef _DEBUG
#include
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#endif


And then at the beggining of my app:

// Get current flag
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
// Turn on leak-checking bit.
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
// Set flag to the new value.
_CrtSetDbgFlag( tmpFlag );


If you do this as anilpanicker is showing then at the end of your program you will receive a very usefull output telling you where exactly you reserved some memory that was never released :D Using this I fixed a small memory leak in Rokoban, very very small, but still it was there. Now I can sleep much better.

There is still a lot of work to be done in my engine. I wish I had all the time in the world to code it but unfortunatelly I have other things to do. Anyway, knowing all those things is always really useful, you never know when you can need them. In the company when I am working at the moment they have their own memory manager implemented. More than that. They have their own asserts. I have learnt from them that if your program can't load a resource the best thing that it can do is telling you and stop. Only in debug mode, of course. This is much better ans easier that trying to make your game work without a graphic loaded of something like that. In your release you should have all your resources so it doesn't make sense to make it work without them :)

Hope any of what I have written will be useful. And take a look at all the links. They were really usefull for me.

4 Comments:

  • Nice article. As a fast and working solution the macro machinery is ideal but later you will discover that those macros can give you problems.

    By Blogger ent, at November 24, 2008 7:13 PM  

  • I Don't have time to make my own memory manager. I really would like to do it. But I have a pending list of things more important at the moment, like sound ;D

    By Blogger Zalo, at November 27, 2008 9:19 PM  

  • I think that is a thing where you have to spend some time at the beginning of your project, but later you will find it very very usefull and will save you a lot of time while trying to discover where the memory leak is :D

    Personally I always follow a basic rule and is: Delete your objects always in the same class where you reserved memory for them. As easy as that. I never had any problems with memory leaks since then...

    P.S.: ¡Hola paisano!

    By Anonymous Anonymous, at August 07, 2009 10:31 PM  

  • That basic rule tends to fail :P as experience shows.

    As an example I have some general functions to load resources, for example to load an image. The data loaded by this function is then stored into an image and the image will be responsible of the deletion of this data at the end of its life. Of course some people would prefer to add this kind of functions as class contructors, but that has its own problems too.

    Things get more complicated if you for example have two objects sharing a texture. Who is responsible for the deletion of the image? The first one because it created the image on the first place? Then what happens if it dies first but the second object still needs it? :)

    By Blogger Zalo, at August 25, 2009 6:37 PM  

Post a Comment

<< Home