Game Development Community

dev|Pro Game Development Curriculum

Memory Leak Detector

by Duncan Gray · 01/29/2006 (3:33 pm) · 8 comments

Please read Pat's HowTo for background information.

That method has the drawback of only showing newly allocated memory and since 99% of memory allocations are legitimate, you have to sift through thousands of lines of useless info and figure which one is not legitimate.

I wanted a method where I could flag everything, just before I start a mission, then after the mission was over, check if any memory created after the flagged point, was not deleted.

I wanted it because I found that in my game, as well the standard starter.fps etc, the game's memory footprint grows by several megs after a mission is run, which implies that not all memory allocated during mission creation gets deleted again.

The following is a variation of some of the tools in platformMemory.cc which will create a list of all the memory allocations not deleted.


Copy and paste the following into platformMemory.cc. Read the comments for usage.
ConsoleFunction(WriteLeaks, void, 1, 1, "WriteLeaks();")
{
	// I used this to try to find things which were created during a mission
	// but not deleted when the mission ended.
	// Ho to use in the above situation?
	// Just before you launch a mission, open the console and type FlagCurrentAllocs();
	// You do that to isolate your leak detection to everything which happens after the 
	// call to FlagCurrentAllocs(); 
	// Next, start your mission, do whats necesary in the mission, exit the mission
	// and open the console again and enter WriteLeaks();
	// Next go look in your game directoy for a file called memoryLeaks.log
	// 
	argc; argv;
	// write out leaks and such
	
	const U32 maxNumLeaks = 1024; // how big a log file do you want?
	U32 numLeaks = 0;
	
	PageRecord * walk;
	AllocatedHeader* pLeaks[maxNumLeaks];
	for (walk = gPageList; walk; walk = walk->prevPage)
		for(Header *probe = walk->headerList; probe; probe = probe->next)
		{
			for(U32 i = 0; i < 4; i++)
			{
				if(probe->preguard[i] != FreeGuard || probe->postguard[i] != FreeGuard)					
					if (!(probe->flags & FlaggityFlag))
					{
						if(numLeaks < maxNumLeaks)
							pLeaks[numLeaks++] = (AllocatedHeader *) probe;
					}
			}
		}	  
		if (numLeaks) 
		{
			char buffer[1024];
			FileStream logFile;
			logFile.open("memoryLeaks.log", FileStream::Write);
			
			for (U32 i = 0; i < numLeaks; i++) 
			{
				dSprintf(buffer, 1023, "Leak in %s: %d %d (%d)\r\n", pLeaks[i]->fileName, pLeaks[i]->line, pLeaks[i]->realSize, pLeaks[i]->allocNum);
				logFile.write(dStrlen(buffer), buffer);
			}
			logFile.close();			
		}
}




.
.

#1
01/30/2006 (5:13 pm)
A handy little console func. Thanks ;)

- Eric
#2
01/31/2006 (8:04 am)
where do I put this, at build I get errors about a declaration in a header
#3
01/31/2006 (8:07 am)
Ok i got it to compile I put it just before
void flagCurrentAllocs()

But it now says (in the console) that it cant find the function.
#4
01/31/2006 (8:15 am)
and in tge 1.4 it has:

// write out leaks and such

const U32 maxNumLeaks = 1024;
U32 numLeaks = 0;

PageRecord * walk;
#ifdef TORQUE_DEBUG_GUARD
AllocatedHeader* pLeaks[maxNumLeaks];
for (walk = gPageList; walk; walk = walk->prevPage)
for(Header *probe = walk->headerList; probe; probe = probe->next)
if ((probe->flags & Allocated) && ((AllocatedHeader *)probe)->fileName != NULL)
pLeaks[numLeaks++] = (AllocatedHeader *) probe;

if (numLeaks && !gNeverLogLeaks) {
if (gAlwaysLogLeaks || Platform::AlertOKCancel("Memory Status", "Memory leaks detected. Write to memoryLeaks.log?") == true) {
char buffer[1024];
FileStream logFile;
logFile.open("memoryLeaks.log", FileStream::Write);

for (U32 i = 0; i < numLeaks; i++) {
dSprintf(buffer, 1023, "Leak in %s: %d (%d)\r\n", pLeaks[i]->fileName, pLeaks[i]->line, pLeaks[i]->allocNum);
logFile.write(dStrlen(buffer), buffer);
}
logFile.close();
}
}


This is a memory leak detector right?
#5
01/31/2006 (12:27 pm)
Quote:
Ok i got it to compile I put it just before void flagCurrentAllocs()

Yes thats a good place to put it.


Quote:
This is a memory leak detector right?

If you are refering to the shutdown() function in platformMemory.cc, it does not work.


Quote:
But it now says (in the console) that it cant find the function.

You need to define TORQUE_DEBUG_GUARD before you can use the memory tools or the console won't know they exist. Perhaps I should have mentioned that but then I would have to repeat most of Pats article.

So for the benefit of those who look at this in the future, depending on your TGE experience, you will need to understand all of Pat's article in order to use this tool effectively.

.
#6
04/27/2006 (11:57 am)
thanks for clearing that up
#7
07/01/2006 (2:27 am)
Holy shit, my memory leak log file is near 1mb!
#8
07/12/2006 (10:20 pm)
Most are just repeats. Ideally the code would need to recognise whether it has already written a particular "problem" but that would involve a second processing loop prior to the write loop.

That second processing loop would need to walk the list once for each item in the list and flag or remove any duplicates. Probably not to hard to do but I have not tried it.