My goal here is to write a small class to keep track of memory I allocate/deallocate so that I can more easily find memory leaks. To do this I overloaded the operators new, new[], delete, and delete[]. In those methods, I allocate/free memory as usual, but also make a call to my MemoryTracker object which stores this information. The MemoryTracker is a singleton.
My problem is that whenever I call new, it seems to get called infinitely many times. This only occurs if the memorytracker is currently up and running (i.e. instantiated from main). If I run this code, once it hits the new char line, it seems to call the new operator over and over with size 24 - no idea why. If anyone sees what I'm doing wrong it would be greatly appreciated!
EDIT: I just realized that in the Allocate() method, whenever I add a pair to the memory map, it is instantiating that pair object, thus the infinite recursion. Can anyone think of a good way to avoid this problem?
Here is my main:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
#include <cstdlib>
#include <iostream>
#include "MemoryTracker.h"
#include "overloaded_new_delete.h"
using namespace std;
MemoryTracker* memory_tracker = 0;
int main(int argc, char *argv[]) {
// Create the memory tracker
memory_tracker = MemoryTracker::Instance();
char* test0 = new char( 'a' );
memory_tracker->PrintStatus();
memory_tracker->Destroy();
system("PAUSE");
return EXIT_SUCCESS;
}
|
Here are my overloaded operators (header file):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
#ifndef __OVERLOAD_NEW_DELETE_H__
#define __OVERLOAD_NEW_DELETE_H__
#include <iostream>
#include <cstdlib>
#include "MemoryTracker.h"
using namespace std;
extern MemoryTracker* memory_tracker;
void* operator new( size_t size );
void* operator new[]( size_t size );
void operator delete( void *p );
void operator delete[]( void *p );
#endif
|
Here are my overloaded operators (implementation):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
#include "overloaded_new_delete.h"
void* operator new( size_t size ) {
void *p = malloc( size );
if (!p)
throw "operator new() error";
cout << p << endl;
cout << size << endl;
system("pause");
if( memory_tracker != 0 ) {
memory_tracker->Allocate( p, size );
}
return p;
}
void* operator new[]( size_t size ) {
void *p = malloc(size);
if (!p)
throw "operator new() error";
if( memory_tracker != 0 ) {
memory_tracker->Allocate( p, size );
}
return p;
}
void operator delete( void *p ) {
free(p);
if( memory_tracker != 0 ) {
memory_tracker->Free( p );
}
}
void operator delete[]( void *p ) {
free(p);
if( memory_tracker != 0 ) {
memory_tracker->Free( p );
}
}
|
Here is my MemoryTracker class header file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
#ifndef __MEMORY_TRACKER_H__
#define __MEMORY_TRACKER_H__
#include <iostream>
#include <map>
#include <fstream>
using namespace std;
class MemoryTracker {
public:
static MemoryTracker* Instance();
static MemoryTracker* Instance( const string& filename );
void Destroy();
void Allocate( const void* ptr, const size_t size );
void Free( const void* ptr );
void PrintStatus();
protected:
MemoryTracker();
~MemoryTracker();
private:
static MemoryTracker* _instance;
map<const void *, const size_t> _memory_map;
static string _OUTPUT_FILENAME;
size_t _total_size;
int _num_pointers;
};
#endif
|
Here is my MemoryTracker class implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
#include "MemoryTracker.h"
// Initialize instance pointer
MemoryTracker* MemoryTracker::_instance = 0;
string MemoryTracker::_OUTPUT_FILENAME = "memorytracker.log";
/**
* CONSTRUCTOR
**/
MemoryTracker::MemoryTracker() {
_memory_map.clear();
_num_pointers = 0;
_total_size = 0;
}
/**
* DESTRUCTOR
**/
MemoryTracker::~MemoryTracker() {
_memory_map.clear();
_num_pointers = 0;
_total_size = 0;
}
/**
* Destroys the instance.
**/
void MemoryTracker::Destroy() {
delete _instance;
_instance = 0;
}
/**
* Returns the instance of this singleton.
**/
MemoryTracker* MemoryTracker::Instance() {
if( _instance == 0 ) {
_instance = new MemoryTracker;
}
return _instance;
}
/**
* Call this when allocating memory with overloaded new or new[].
**/
void MemoryTracker::Allocate( const void* ptr, const size_t size ) {
_memory_map.insert( pair<const void*, const size_t>( ptr, size ) );
_total_size += size;
_num_pointers++;
}
/**
* Call this when freeing memory with delete or delete[].
**/
void MemoryTracker::Free( const void* ptr ) {
size_t size = _memory_map[ ptr ];
_memory_map.erase( ptr );
_total_size -= size;
_num_pointers--;
}
/**
* Prints the status of all the allocated memory being tracked to file.
**/
void MemoryTracker::PrintStatus() {
// Open the log file for output
ofstream out( _OUTPUT_FILENAME.c_str() );
// Print Totals
out << "Total Number of Pointers: " << _num_pointers << endl;
out << "Total Size Allocated: " << _total_size << endl;
out << endl << endl;
// Print specific info about each pointer
out << "Pointer Information:" << endl;
map< const void*, const size_t >::iterator it;
for( it = _memory_map.begin(); it != _memory_map.end(); it++ ) {
out << "Address: " << it->first << " Size: " << it->second << endl;
}
// Close log file
out.close();
}
|