Jump to content
  • Advertisement
Sign in to follow this  
TheBob

Memory tracker

This topic is 4486 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I would like to write a series of functions which I can use in my applications which can track current memory usage by the application (so I can identify memory leaks) and I would also like to be able to identify and catch exceptions. If this is possible, would someone please point me in the right direction. I realise it's not a menial task, but right now I dont even know where to start looking. This kind of cuntionality would be invaluble. Many thanks, TheBob

Share this post


Link to post
Share on other sites
Advertisement
The following is a simplified version of the code I use to perform memory tracking...


//-----------------------------------------------------------------------------
// File : MemoryLeakTracker.h
// Author : Shaun Dwane White
// Creation Date : 03-04-06
// Revision Date : 03-04-06
// Version : 1.0
//
// Notes : Header file for MemoryLeakTracker.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Header file inclusion guard.
//-----------------------------------------------------------------------------
#ifndef MEMORY_LEAK_TRACKER__H
#define MEMORY_LEAK_TRACKER__H

//-----------------------------------------------------------------------------
// Standard includes for this header file to work.
//-----------------------------------------------------------------------------
#include <windows.h>
#include <crtdbg.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

//-----------------------------------------------------------------------------
// Microsoft specific compiler symbol, that is defined during DEBUG builds and
// undefined during RELEASE builds. This flag is used to ensure that the
// memory tracking macros are only defined in DEBUG builds.
//-----------------------------------------------------------------------------
#ifdef _DEBUG

//-----------------------------------------------------------------------------
// DEBUG Macros:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// SNAP_HEAP:
// Takes a snap shot of the current debug heap. MUST be used in conjuntion
// with a following TEST_HEAP macro in the SAME code statement block.
//
// TEST_HEAP:
// Takes another snap shot of the debug heap and compares it with the previous
// snap shot obtained by the previous SNAP_HEAP macro. If there is a
// difference, then a message box will appear, warning you that a leak has
// occurred. The message box will also display the file and line number where
// the detection took place, as well as giving you the option to continue or
// abort the program.
//
// Notes:
// Simply detecting a leak is sufficient for my purposes, but you could alter
// the code easily to determine just how much bytes were leaked and in what
// heap etc. You can even obtain a dump of the heap statistics if you like...
// Just check out the _CrtMem... functions defined in "crtdbg.h" and explained
// in MSDN.
//
// Also note that the _CrtMem... functions are DEBUG only functions.
//-----------------------------------------------------------------------------
#define SNAP_HEAP *
{ *
_CrtMemState oldHeap; *
*
_CrtMemCheckpoint (&oldHeap); *
{

#define TEST_HEAP *
} *
_CrtMemState newHeap, heapDifference; *
_TCHAR msgBoxText [MAX_PATH + 1]; *
*
_CrtMemCheckpoint (&newHeap); *
if (_CrtMemDifference (&heapDifference, &oldHeap, &newHeap)) *
{ *
_sntprintf *
( *
msgBoxText, MAX_PATH, _TEXT ("Memory leak detected!\n\nIn file:\n%s\n\nAt line:\n%d\n\nExit process?"), *
_TEXT (__FILE__), __LINE__ *
); *
msgBoxText[MAX_PATH] = 0; *
if (MessageBox (0, msgBoxText, TEXT ("Memory Leak!!!"), MB_YESNO | MB_ICONWARNING) != IDNO) ExitProcess (EXIT_FAILURE); *
} *
}

//-----------------------------------------------------------------------------
// SNAP_HEAP_STATE (heap):
// Takes a snap shot of the debug heap and stores the result in "heap". This
// is a more flexible version of the SNAP_HEAP macro, because if "heap" is
// defined globally, then you don't necessarily have to perform a test in the
// same code block.
//
// TEST_HEAP_STATE (heap):
// Performs exactly like the TEST_HEAP macro, except it now tests the "heap"
// variable.
//
// Notes:
// These macros are more flexible than the previous pair, as it can detect
// memory leaks that occur across function calls. Useful for general
// programming issues as well as detecting leaks in DLLs (provided you perform
// the test in DllMain's DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH cases).
//
// The variable "heap" MUST be of the type: _CrtMemState
//-----------------------------------------------------------------------------
#define SNAP_HEAP_STATE(heap) _CrtMemCheckpoint (static_cast<_CrtMemState *> (&heap));

#define TEST_HEAP_STATE(oldHeap) *
{ *
_TCHAR ___msgBoxText [MAX_PATH + 1]; *
_CrtMemState ___newHeap, ___heapDifference; *
*
_CrtMemCheckpoint (&___newHeap); *
if (_CrtMemDifference (&___heapDifference, static_cast<const _CrtMemState *> (&oldHeap), &___newHeap)) *
{ *
_sntprintf *
( *
___msgBoxText, MAX_PATH, _TEXT ("Memory leak detected!\n\nIn file:\n%s\n\nAt line:\n%d\n\nExit process?"), *
_TEXT (__FILE__), __LINE__ *
); *
___msgBoxText[MAX_PATH] = 0; *
if (MessageBox (0, ___msgBoxText, TEXT ("Memory Leak!!!"), MB_YESNO | MB_ICONWARNING) != IDNO) ExitProcess (EXIT_FAILURE); *
} *
}

//-----------------------------------------------------------------------------
// RELEASE Macros:
// Ensures that all memory tracking macros are omitted in RELEASE builds.
//-----------------------------------------------------------------------------
#else

#define SNAP_HEAP
#define TEST_HEAP

#define SNAP_HEAP_STATE(heap) 0;
#define TEST_HEAP_STATE(oldHeap) 0;

#endif // _DEBUG
#endif // MEMORY_LEAK_TRACKER__H




IMPORTANT NOTE!!! If you copy and paste the above code, you must turn all ending '*' characters into backslash characters '\'. For some reason
(my English keyboard I think), '\' characters don't print very well here.

Here is a source code example of how one would this code:


#include "MemoryLeakTracker.h"

#ifdef _DEBUG
_CrtMemState debugHeap;
#endif // _DEBUG

void MemoryLeakFunction (PBYTE memoryLeak)
{
if (memoryLeak) memoryLeak = new BYTE;
}

int main ()
{
PBYTE memoryLeakOne;
PBYTE memoryLeakTwo;

//----------------------------------------------------------------------------------------------------------------------------------------
// SNAP_HEAP, TEST_HEAP example:
//----------------------------------------------------------------------------------------------------------------------------------------
SNAP_HEAP
{
memoryLeakOne = new BYTE;
}
TEST_HEAP

//----------------------------------------------------------------------------------------------------------------------------------------
// SNAP_HEAP_STATE, TEST_HEAP_STATE example:
//----------------------------------------------------------------------------------------------------------------------------------------
SNAP_HEAP_STATE (debugHeap)
MemoryLeakFunction (memoryLeakTwo);
TEST_HEAP_STATE (debugHeap)

return EXIT_SUCCESS;
}




And here is a simplified version of the code I use for handling exceptions:


//-----------------------------------------------------------------------------
// File : SimpleExceptionHandler.h
// Author : Shaun Dwane White
// Creation Date : 03-04-06
// Revision Date : 03-04-06
// Version : 1.0
//
// Notes : Header file for SimpleExceptionHandler.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Header file inclusion guard.
//-----------------------------------------------------------------------------
#ifndef SIMPLE_EXCEPTION_HANDLER__H
#define SIMPLE_EXCEPTION_HANDLER__H

//-----------------------------------------------------------------------------
// Standard include for this header file to work.
//-----------------------------------------------------------------------------
#include <windows.h>

//-----------------------------------------------------------------------------
// Exception structure declarations:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// General EXCEPTION structure declaration:
//
// This structure is thrown when a general exception is raised and is used as
// a BASE structure for all other types of exceptions.
//-----------------------------------------------------------------------------
struct EXCEPTION
{
LPCTSTR ITS_MSG; // The exception's message string.
LPCTSTR ITS_FILE; // The name of the file in which the exception is thrown.
DWORD itsLine; // The line number where the exception was thrown.
PVOID itsParam; // Extra parameter for future expansion.

EXCEPTION (LPCTSTR, LPCTSTR, DWORD, PVOID = 0);
};

//-----------------------------------------------------------------------------
// MEMORY_EXCEPTION structure declaration:
//
// This structure is specifically thrown when memory can no longer be allocated.
//-----------------------------------------------------------------------------
struct MEMORY_EXCEPTION : public EXCEPTION
{
MEMORY_EXCEPTION (LPCTSTR, LPCTSTR, DWORD, PVOID = 0);
};

//-----------------------------------------------------------------------------
// You could introduce further exception structures here in a similar way, like
// DRIVE_EXCEPTION for disk drive problems, or GRAPHICS_EXCEPTION for video
// card problems etc.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Exception structure inlined implementations:
//
// These structures are pretty simple, so we may as well inline their
// implementations here in this header file. They'll perform a bit quicker too!
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// General EXCEPTION structure implementation:
//-----------------------------------------------------------------------------
inline EXCEPTION::EXCEPTION (LPCTSTR MSG, LPCTSTR FILE, DWORD line, PVOID param):
ITS_MSG (MSG),
ITS_FILE (FILE),
itsLine (line),
itsParam (param)
{
}

//-----------------------------------------------------------------------------
// MEMORY_EXCEPTION structure implementation:
//-----------------------------------------------------------------------------
inline MEMORY_EXCEPTION::MEMORY_EXCEPTION (LPCTSTR MSG, LPCTSTR FILE, DWORD line, PVOID param):
EXCEPTION (MSG, FILE, line, param)
{
}

#endif // SIMPLE_EXCEPTION_HANDLER__H





And finally, here is a source code example of how one would use this simple exception handler:


#include "ExceptionHandler.h"

#include <stdio.h>
#include <tchar.h>

void PrintException (const EXCEPTION &EXCEPTION)
{
_tprintf ("ITS_MSG\t\t%s\n", EXCEPTION.ITS_MSG);
_tprintf ("ITS_FILE\t%s\n", EXCEPTION.ITS_FILE);
_tprintf ("itsLine\t\t%u\n", EXCEPTION.itsLine);
_tprintf ("itsParam\t%s\n\n", EXCEPTION.itsParam);
}

int main ()
{
//-----------------------------------------------------------------------------
// Throw and catch a general exception:
//
// Note:
// The pre-defined symbols __FILE__ is turned into a string which contains the
// filename of the current file by the compiler during compilation.
//
// The pre-defined symbols __LINE__ is tured into the current code line number
// by the compiler during compilation.
//-----------------------------------------------------------------------------
try
{
throw EXCEPTION (_TEXT ("General Exception Thrown!"), __FILE__, __LINE__);
}
catch (EXCEPTION &EXCEPTION)
{
PrintException (EXCEPTION);
}
catch (...)
{
puts ("An unknown exception has been caught!");
}

//-----------------------------------------------------------------------------
// Throw and catch a memory exception:
//
// Note:
// If you specifically wanted to catch memory exception, you must place them
// ABOVE the code where general or undefined exceptions would be caught.
//-----------------------------------------------------------------------------
try
{
throw MEMORY_EXCEPTION (_TEXT ("Out Of Memory!"), __FILE__, __LINE__);
}
catch (MEMORY_EXCEPTION &MEMORY_EXCEPTION)
{
PrintException (MEMORY_EXCEPTION);
}
catch (EXCEPTION &EXCEPTION)
{
PrintException (EXCEPTION);
}
catch (...)
{
puts ("An unknown exception has been caught!");
}

return 0;
}





Please feel free to copy and paste the code if it suits your needs.

I hope this helps!

[Edited by - TerrorFLOP on April 3, 2006 12:53:56 AM]

Share this post


Link to post
Share on other sites
If you're using Visual C++, you could also use their memory trakcer with

#include <crtdbg.h> // in the stdafx.h
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); // in the main entry point of your program

It will prints in the debug output of visual a list of all the memory links, with an allocID. With this allocID, you can then re-execute the program, and break when it is reached, using this line :

_CrtSetBreakAlloc(5031); // where 5031 is the allocID reported by the previous execution

Share this post


Link to post
Share on other sites
Quote:
Original post by TerrorFLOP
...


You mix C and C++ code. The cast static_cast is not available in C, the headers stdlib.h and stdio.h aren't available in C++. There is some other stuff which also is only in one of the languages. Your code mostly looks like C with some stuff borrowed from C++, but this isn't standard. If it's supposed to be C++ code then you should not use the C functions like _sntprintf, _tprintf etc. Instead you should use the C++ standard library (You would need streams). Also you know in C++ (not sure about C) you are not allowed (well it might just result in undefined behavior, can't remember, but it's not guareented to act like a normal variable) to start your variable names with __ (two underscores), since those are reserved for the compiler..

Share this post


Link to post
Share on other sites
stdio.h, stdlib.h, etc., as well as the *printf family of functions are all perfectly legal C++.

Share this post


Link to post
Share on other sites
I've been mixing C and C++ for years.

It's ALL perfectly legal under MS Visual C++ 6.0.

As my old grandma used to say...

'If you can, have the best of both worlds...'

I tend to use TRIPLE underscoring in my #define symbols.

This is my OWN programming style (again perfectly legal), which ensures I don't have a symbol clash with other #defines. And since some symbols have DOUBLE underscoring... I thought TRIPLE underscoring would be a wise precaution, considering that #define symbols cannot be namespaced.

Again, my own style... That suits me just fine thx!

BTW... Double underscoring or indeed single underscoring... Or having varibles and symbols that start with TEN underscores is ALL prefectly legal (C/C++ are very flexible), so long as you don't have a clash with an already defined variable or symbol.

Share this post


Link to post
Share on other sites
Quote:
Original post by Omaha
stdio.h, stdlib.h, etc., as well as the *printf family of functions are all perfectly legal C++.


stdio.h, stdlib.h, etc are NOT part of C++. You're thinking of cstdio, cstdlib, etc. Which are the C++ headers that support the C89 standard library.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!