Skip to main content
GameDev.net gamedev.net
🔒 Locked

Tracking memory leaks in C++

Started by Samith Aug 5, 2007 at 10:50 AM 33 replies 7.9k views
Original Post
Samith
Samith
Memory leaks as we all know are an annoying problem. But again I'm sort of hung up trying to think of a way to avoid them. I know how smart/intrusive pointers work and how to use them, but this feels like an incomplete solution. If I forget to use a smart pointer I could potentially leave some memory undeleted, thus causing a leak. I'm wondering what people have used as solutions to memory problems. Ideally I'd like some sort of solution that causes a very clear runtime error if a memory leak is allowed. It should allow me to see what memory I forgot to delete, etc. Currently the only solution I can think of is to allocate some big pool of memory at the beginning of my program, then force (somehow, overloaded new perhaps?) everyone to use that pool and tag the memory they allocate so that at the end of the program I can see if there are any remaining tags. The problem is that this solution seems somewhat inflexible. Is this much security even necessary? Are there other possible solutions that anyone knows of? I know this is a very broad subject and the correct solution depends highly on what type of application is being written, but I think for now I'd just like to see what solutions people have used to give me an idea of what's out there. Any ideas would be appreciated. Sam
SiCrane
SiCrane
Your compiler/runtime library may have leak tracking functionality built in. For example with MSVC you can use _CrtDumpMemoryLeaks() or _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ).
Samith
Samith
Wow, thanks for the fast responses. Those look like very handy tools. Are these Microsoft specific, though? I am currently using MSVC but I would also like to know some solutions that would be portable to other development environments.

Great advice, though, I will certainly try to make use of this functionality.
fpsgamer
fpsgamer
purify

and

valgrind

Basically, not matter what major platform you're on, something will be available.
Verg
Verg
Paul Nettle's Memory Manager has worked well for me.

As far as the smart pointer discussion goes... why not just use all smart pointers?

If you have a lot of refactoring to do to get to that point... you can start to introduce them a little at a time until you get your memory leaks under control.

The Loki Library is lightweight and has a very nice Smart pointer template. boost::shared_ptr is a great option too.
Zahlman
Zahlman
Or, just don't create memory leaks. :)
UltimateWalrus
UltimateWalrus
This is a pretty simple solution. But it works for me a lot of the time.

Create two functions:

int Allocations = 0;inline void *dmalloc(unsigned long size){  Allocations++;  return malloc(size);}inline void dfree(void *pointer){  Allocations--;  free(pointer);}


Or something like that. If you want to use "new" and "delete" that's OK too. I haven't compiled this, but it should work.

At the end of the program, just check the "Allocations" variable; it should be 0. If it's not, you have a memory leak (although you'll have to figure out where by yourself). ;)
fpsgamer
fpsgamer
Quote:
Original post by UltimateWalrus
At the end of the program, just check the "Allocations" variable; it should be 0. If it's not, you have a memory leak (although you'll have to figure out where by yourself). ;)


That method is somewhat problematic. Consider the fact that you may have pointers that last for the entire life of the application. You do not have to bother deleting these since all memory your application claims during execution is returned to the system after termination anyways.

A memory leak involves you "losing handles" to memory during execution

ie.

int* a = new int[100];
a = (int*)5; // how the hell do we access our array now?

Now that memory is now lost for the entire execution of the application.

Using a more advanced tool will give you information about which pointers have not been free'd, not just that some stuff hasn't been free'd.
Evil Steve
Evil Steve
My memory manager; Overloads operators new and delete, has some stack walking functions to determine where allocations came from, is thread safe, and works with X64:
PMemory.h, PMemory.cpp.
That code won't compile straight out of the box, but it should with some minor modifications (E.g. removing my assert calls and so on). It should work with other compilers (untested), the only MSVC specific part I know of is the #pragma init_seg(compiler) call (Which is there to ensure the memory manager global is constructed before STL globals, so it can track STL "leaks").
fpsgamer
fpsgamer
Quote:
Original post by Evil Steve
My memory manager; Overloads operators new and delete, has some stack walking functions to determine where allocations came from, is thread safe, and works with X64:
PMemory.h, PMemory.cpp.
That code won't compile straight out of the box, but it should with some minor modifications (E.g. removing my assert calls and so on). It should work with other compilers (untested), the only MSVC specific part I know of is the #pragma init_seg(compiler) call (Which is there to ensure the memory manager global is constructed before STL globals, so it can track STL "leaks").


Have you considered releasing the EvilSteve standard library so we can all easily accumulate all the code you've posted? [grin]
UltimateWalrus
UltimateWalrus
Quote:
Original post by fpsgamer
That method is somewhat problematic. Consider the fact that you may have pointers that last for the entire life of the application. You do not have to bother deleting these since all memory your application claims during execution is returned to the system after termination anyways.

A memory leak involves you "losing handles" to memory during execution

ie.

int* a = new int[100];
a = (int*)5; // how the hell do we access our array now?

Now that memory is now lost for the entire execution of the application.

Using a more advanced tool will give you information about which pointers have not been free'd, not just that some stuff hasn't been free'd.


But isn't it still good practice to clean up all your memory resources when the program terminates? I'm just a novice, so you probably know more about it than I do :)

I don't doubt that an advanced tool would be useful (especially for a large-scale game). But rather than downloading a whole framework for my little projects, I'd rather just try to use good programming practice. Every time I make an allocation, I usually go down right away and put a free somewhere. Granted, this won't prevent the error you described (setting the pointer to a new value), but it can prevent memory leaks, say, when a pointer variable goes out of scope. My point is, there are ways of programming that can minimize the risks of memory leaks.
Evil Steve
Evil Steve
Quote:
Original post by UltimateWalrus
But isn't it still good practice to clean up all your memory resources when the program terminates? I'm just a novice, so you probably know more about it than I do :)
Yup, definitely.

Quote:
Original post by UltimateWalrus
My point is, there are ways of programming that can minimize the risks of memory leaks.
Minimise, yes. Remove, no. This is just one cause of a memory leak, there's loads of other things that can cause them.
fpsgamer
fpsgamer
Quote:
Original post by UltimateWalrus
Quote:
Original post by fpsgamer
That method is somewhat problematic. Consider the fact that you may have pointers that last for the entire life of the application. You do not have to bother deleting these since all memory your application claims during execution is returned to the system after termination anyways.

A memory leak involves you "losing handles" to memory during execution

ie.

int* a = new int[100];
a = (int*)5; // how the hell do we access our array now?

Now that memory is now lost for the entire execution of the application.

Using a more advanced tool will give you information about which pointers have not been free'd, not just that some stuff hasn't been free'd.


But isn't it still good practice to clean up all your memory resources when the program terminates? I'm just a novice, so you probably know more about it than I do :)

I don't doubt that an advanced tool would be useful (especially for a large-scale game). But rather than downloading a whole framework for my little projects, I'd rather just try to use good programming practice. Every time I make an allocation, I usually go down right away and put a free somewhere. Granted, this won't prevent the error you described (setting the pointer to a new value), but it can prevent memory leaks, say, when a pointer variable goes out of scope. My point is, there are ways of programming that can minimize the risks of memory leaks.


Ya, I think my phrasing was a little strong.

That method isn't as bad an I may have made it sound.
Verg
Verg
Quote:
Original post by UltimateWalrus
I don't doubt that an advanced tool would be useful (especially for a large-scale game). But rather than downloading a whole framework for my little projects,


Paul Nettle's is easy and consists of two (well, three) files. Evil Steve's (obviously) consists of just two files. It's worth it [smile]
CrazyCdn
CrazyCdn
Quote:
Original post by Evil Steve
My memory manager; Overloads operators new and delete, has some stack walking functions to determine where allocations came from, is thread safe, and works with X64:
PMemory.h, PMemory.cpp.
That code won't compile straight out of the box, but it should with some minor modifications (E.g. removing my assert calls and so on). It should work with other compilers (untested), the only MSVC specific part I know of is the #pragma init_seg(compiler) call (Which is there to ensure the memory manager global is constructed before STL globals, so it can track STL "leaks").


You could wrap that #pragma in a #ifdef or simular to make it only included in MSVC compilers? I haven't looked at your code but might be an idea. Just for your sake later too?
"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin
taby
taby
If you're absolutely worried about memory leaks, use vector's contiguous memory layout. Deconstructor takes care of memory release, removing the need for pointer-based arrays.

When allocating/instantiating a single object through a pointer though, the extra memory and speed requirement of the vector class may not be worth it.

Also, one could build a registration class which tracks memory allocation through pointers by exposing member functions that are used in proxy of direct calls to new/new[] and delete/delete[]. This way the member function can examine the existing state of the pointer in question, and deallocate it if need be before allocating.

#include <iostream>using std::cout;using std::endl;#include <new>using std::nothrow;template<class T>bool array_alloc(T *&ptr, size_t elems = 0){	// T **ptr_to is used to compare against the database.	// Memory cost of tracking this pointer in the database	// is sizeof(T**).	T **ptr_to = &ptr	bool is_allocated = false;	if(0 == elems)		return is_allocated; // false	// If this address is found in the database,	// it is passed to delete[].	if(0 != *ptr_to)		delete [] *ptr_to;	// Upon failure, return 0 instead of throwing std::bad_alloc.	*ptr_to = new(nothrow) T[elems*sizeof(T)];	if(0 == *ptr_to)		return is_allocated; // false;	else		is_allocated = true;	for(size_t i = 0; i < elems; i++)		(*ptr_to) = 0;	return is_allocated; // true}int main(void){	size_t size = 10;	char *y = 0;	array_alloc(y, size);	cout << static_cast<int>(y[size - 1]) << endl;		// When the database class goes out of scope,	// all known allocated pointers are passed to delete[].	return 0;}


Edit: changed the source.

[Edited by - taby on August 5, 2007 11:57:23 PM]
David Neubelt
David Neubelt
Quote:
Original post by Zahlman
Or, just don't create memory leaks. :)


I wish it was that simple life would be great :P

I just spent the last three weeks writing custom software to track memory leaks and you'd be suprised on how many different ways you can leak memory.

The solution I've come up with is hook into new/placement new/malloc and your OS's allocation calls. Then write a function to walk up the stack, and based on the program counter look up the function name in the map file for the executable. This has given me the quickest way to track down memory leaks.

-= Dave
Graphics Programmer - Ready At Dawn Studios
Deaken Frost
Deaken Frost
If you are using MSVC you can also use Visual Leak Detector (http://dmoulding.googlepages.com/vld). It's very easy to use and the least intrusive method I have seen. It only works in debug mode, however.
moosedude
moosedude
If you're having trouble with memory, maybe consider a different design methodology for your new programs that naturally enforce memory construction/destruction rules. Each time I create a new class I write a standard set of functions that are called on construction and destruction of the class, it works very well.

Failing that, if you're considering overload the memory allocation functions, you may as well go the whole journey and create your own simple memory manager, that way you can be exceptional messy when allocating memory and just delete your memory manager pool at the end of the program. I personal think this is a brillant way of creating prototypes really quickly when you don't want to think about memory management.
http://www.fotofill.co.uk

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.