⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memorymanager.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/***
 * File:   MemoryManager.cpp - Implements MemoryManager.h
 *         -----------------------------------------------------
 * Author: Peter Dalton
 * Date:   3/23/01 1:23:45 PM
 *
 * Description:
			This Memory Manager software provides the following functionality:
			  1. Seamless interface.
			  2. Tracking all memory allocations and deallocations.
				3. Reporting memory leaks, unallocated memory.
				4. Reporting memory bounds violations.
				5. Reporting the percentage of allocated memory that is actually being used.
				6. Customizable tracking.

	    The code is self documented, thus reading through this implementation file should 
			explain how everything is implemented and the reasoning behind it.
 *
 * Copyright (C) Peter Dalton, 2001. 
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied warranties. You may freely copy 
 * and compile this source into applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 *                  "Portions Copyright (C) Peter Dalton, 2001"
 */

#include <string.h>           // It is important to note here the order in which the files are
#include <stdarg.h>           // included to avoid syntax and linking errors.  First you should
#include <stdio.h>            // include all of the required standard header files followed by
#include <time.h>             // the MemoryManager.h header.  All other custom file should be
#include <assert.h>           // included after the MemoryManager.h header. 
 
#include "MemoryManager.h"    

/*******************************************************************************************/
/*******************************************************************************************/
// ***** Implementation:

#ifdef ACTIVATE_MEMORY_MANAGER  // Only execute if the memory manager has been enabled.

/*******************************************************************************************/
// Turn off the defined macros to avoid confusion.  We want to avoid circular definition, 
// it is also not desired to track memory allocations within the memory manager module.
#include "new_off.h"

// Define our own version of assert to simply set a break point.
#define m_assert(x) if ((x) == false) __asm { int 3 }  // Set a break point

/*******************************************************************************************/
// ***** Global Variables Definitions:

const long PADDING          = 0xDEADC0DE;
const long BODY             = 0xBAADC0DE;
const char BREAK_ON_DEALLOC = 0x1;
const char BREAK_ON_REALLOC = 0x2;
const int  HASH_SIZE        = 1024;
int   NumAllocations        = 0;
char  LOGFILE[40]           = "memoryLogFile.log"; 
const char* const s_allocationTypes[] = { "Unknown", "new", "new[]", "malloc", "calloc",
                                          "realloc", "delete", "delete[]", "free" };


/*******************************************************************************************/
// ***** Here are the containers that make up the memory manager.  

struct StackNode {                  // This struct is used to hold the file name and line
	const char *fileName;             // number of the file that is requesting a deallocation.
	unsigned short lineNumber;        // Only deallocations are recorded since the allocation
	StackNode *next;                  // routines accept these additional parameters.
};

struct MemoryNode                   // This struct defines the primary container for tracking
{                                   // all memory allocations.  It holds information that 
  size_t         actualSize;        // will be used to track memory violations and information
  size_t         reportedSize;      // to help the user track down specific problems reported
  void          *actualAddress;     // to the log file upon termination of the program.
  void          *reportedAddress;   
  char           sourceFile[30];    // I have tried to keep the physical size of this struct
  unsigned short sourceLine;        // to a minimum, to reduce the memory tracking overhead.  
	unsigned short paddingSize;       // At the same time I have tried to allow for as much
  char           options;           // flexibility and information holding as possible.
	long           predefinedBody;
  ALLOC_TYPE     allocationType;
  MemoryNode    *next, *prev;

	void InitializeMemory( long body = BODY ) ; // Initailize the nodes memory for interrogation.
};

// This class implements a basic stack for record keeping.  It is necessary to use this class
// instead of the STL class since we need to explicitly call the init() method to initialize
// the data members.  This is due to the restriction of only using the malloc() method within
// this file to avoid calling our own new() method and creating circular definitions.  It is 
// necessary to create this stack for logging file information when deallocating memory due to
// to order in which memory is deallocated and the effect of the delete macro.  To understand
// this better refer to the sample illustration below.
// 
//    Sample Code     file1 => delete classAObject;
//                    file2 => ~classA() { delete[] intArray; }
//    
//    Function Calls      1.  setOwner( file1, line );
//                        2.  setOwner( file2, line );
//                        3.  deAllocate( intArray, MM_DELETE_ARRAY );
//                        4.  deAllocate( classAObject, MM_DELETE );
//
// The order of operations requires a stack for proper file tracking.
class myStack
{
public:
	myStack() {}
	__inline void init() 
		{ m_head = NULL; m_count = 0; }
	__inline bool empty() 
		{ return (m_count == 0); }
	__inline StackNode* top() 
		{ return m_head; }
	__inline void push( StackNode *n ) 
		{ if (!n) return; n->next = m_head; m_head = n; m_count++; }
	__inline StackNode* pop()  
		{ StackNode *n = m_head; if (n) m_head = m_head->next; m_count--; return n; } 
private:
	StackNode *m_head;
	int m_count;
};

// This class provides the implementation for the Memory Manager.  I created this class to 
// act as a container to centeralize the control instead of allowing everyone to become 
// intertangled.  Be design I have also left a lot of data members public for ease of access
// since this file is the only one that can ever create a MemoryManager object.
class MemoryManager
{
public:
  MemoryManager( void )  {};    // Default Constructor.
  ~MemoryManager( void ) {};    // Destructor.

	void initialize( void );      // Initailize internal memory.
	void release( void );         // Release internal memory.

	// Hash Table Routines
	void insertMemoryNode( MemoryNode *node );      // Insert a new memory node.
	MemoryNode *getMemoryNode( void *address );     // Retrieve a memory node.
	MemoryNode *removeMemoryNode( void *address );  // Remove a memory node.
	bool validateMemoryUnit( MemoryNode *node );    // Validate a memory node's memory.

	// Memory Caching to minimize allocations within the memory manager
	void deallocateMemory( MemoryNode *node );
	MemoryNode* allocateMemory( void );

	// Error Reporting Routines
	void dumpLogReport( void );
	void dumpMemoryAllocations( void );
	void log( char *s, ... );
	
	// User programmable options
	int           m_breakOnAllocationCount;
	unsigned int  m_paddingSize;
	bool          m_logAlways;
	bool          m_cleanLogFileOnFirstRun;

	// Statistical Information
	int          m_totalMemoryAllocations;  // The number of allocations.
	unsigned int m_totalMemoryAllocated;    // Number of bytes allocated.
	unsigned int m_totalMemoryUsed;         // Number of bytes used.
	
	unsigned int m_peakMemoryAllocation;    // The largest memory allocation.
	unsigned int m_peakTotalNumAllocations; // The largest number of allocation existing simaltaniously.
	unsigned int m_overheadMemoryCost;      // The current amount of memory required for memory tracking.
	unsigned int m_peakOverHeadMemoryCost;  // The peak overhead memory cost.
	unsigned int m_totalOverHeadMemoryCost; // The total overhead memory cost. 
	unsigned int m_allocatedMemory;         // The current amount of allocated memory.
	unsigned int m_numBoundsViolations;     // The number of memory bounds violations.

	// Stack for tracking file information for deallocations.
	myStack m_topStack;

	unsigned int m_numAllocations;      // The number of entries within the hash table.
private:
	int getHashIndex( void *address );  // Given an address this returns the hash table index
	int calculateUnAllocatedMemory();   // Return the amount of unallocated memory.

	MemoryNode *m_hashTable[HASH_SIZE]; // Hash Table container for tracking memory allocations.

	MemoryNode *m_memoryCache;          // Used for caching unused memory nodes.
};
MemoryManager *s_manager = NULL;      // Declaration of the one and only Memory Manager Object 


/*******************************************************************************************/
// ***** Function Prototypes:  Refer to implemations below for additional details.

bool InitializeMemoryManager( void );
void releaseMemoryManager( void );
char *formatOwnerString( const char *file, int line );
char *sourceFileStripper( const char *sourceFile );
void log( char *s, ... );
char *insertCommas( unsigned long value );
char *memorySizeString( unsigned long size, bool lengthenString = true );


/*******************************************************************************************/

/**
 * AllocateMemory():
 *  This is the main memory allocation routine, this is called by all of the other 
 *  memory allocation routines to allocate and track memory.
 * 
 *  Return Type: void 
 *  Arguments: 
 *  	const char *file	   : The file requesting the deallocation.
 *  	int line	           : The line within the file requesting the deallocation.
 *    size_t size          : The size of the memory to be reallocated.
 *  	ALLOC_TYPE type	     : The type of reallocation being performed.
 */
void *AllocateMemory( const char *file, int line, size_t size, ALLOC_TYPE type, void *address ) 
{
	MemoryNode *memory;

	// If the memory manager has not yet been initialized due to the order in which static
	// variables are allocated, create the memory manager here.
	if (!s_manager && !InitializeMemoryManager()) {
		if (NumAllocations != 0) {
			log( "The Memory Manager has already been released from memory, however an allocation was requested" );
			log( "\t%-40s", formatOwnerString( file, line ) );
		}
		return malloc( size );  // Try to allocate the memory for the requesting process. 
	}

  if (size == 0) size = 1; // ANSI states that allocation requests of size 0 should return
	                         // a valid pointer.
		
	// Has the user requested to break on the N-th allocation.
  m_assert( s_manager->m_totalMemoryAllocations != s_manager->m_breakOnAllocationCount );

  // If the type is UNKNOWN then this allocation was made from a source not set up to 
  // use memory tracking, include the MemoryManager header within the source to elimate
  // this error.
  m_assert( type != MM_UNKNOWN );

	if (type == MM_REALLOC) {
		MemoryNode *memory = s_manager->removeMemoryNode( address );

		// Validate that the memory exists
		m_assert( memory );
		if (!memory) {
			s_manager->log( "Request to reallocate RAM that was never allocated." );
		}

	  // Validate that there is not a allocation/reallocation mismatch
		m_assert( memory->allocationType == MM_MALLOC ||
			        memory->allocationType == MM_CALLOC ||
				      memory->allocationType == MM_REALLOC );

		// Validate that a break point on reallocation has not been requested.
		m_assert( (memory->options & BREAK_ON_REALLOC) == 0x0 );

		memory->actualSize    = size + s_manager->m_paddingSize * sizeof(long)*2;
		memory->reportedSize  = size;
		memory->actualAddress = realloc( memory->actualAddress, memory->actualSize );
	}
	else {
		// Create a new memory block for tracking the memory
		memory = s_manager->allocateMemory();

		// Validate the memory node allocation
		m_assert( memory != NULL );
		if (memory == NULL) {
			s_manager->log( "Could not allocate memory for memory tracking.  Out of memory." );
		}

		memory->actualSize        = size + s_manager->m_paddingSize * sizeof(long)*2;
		memory->reportedSize      = size;
		memory->actualAddress     = malloc( memory->actualSize );
		memory->options           = 0;
	}

  memory->reportedAddress   = (char*)memory->actualAddress + s_manager->m_paddingSize * sizeof(long);
  memory->sourceLine        = line;
	memory->paddingSize       = s_manager->m_paddingSize;
  memory->allocationType    = type;
  strcpy( memory->sourceFile, sourceFileStripper( file ) );

	if (s_manager->m_logAlways) {
    s_manager->log( "Memory Allocation        : %-40s %8s(0x%08p) : %s", formatOwnerString( file, line ),
                    s_allocationTypes[type], memory->reportedAddress, memorySizeString( size ) );
  }

  // Validate the memory allocated
  m_assert( memory->actualAddress );
  if (!memory->actualAddress) {
		s_manager->log( "Request for allocation failed.  Out of memory." );
  }

  // Initialize the memory allocated for tracking upon deallocation
  if (type == MM_CALLOC) memory->InitializeMemory( 0x00000000 );
  else                   memory->InitializeMemory( 0xBAADC0DE );
  

  // Insert the memory node into the hash table, this is a linked list hash table.
	s_manager->insertMemoryNode( memory );
  return memory->reportedAddress;
}

/*******************************************************************************************/

/**
 * deAllocateMemory():
 *  This is the main memory de-allocation routine.  This method is used by all of the 
 *  other de-allocation routines for de-allocating and tracking memory.
 * 
 *  Return Type: void 
 *  Arguments: 
 *  	void *address	       : The address of memory to be deallocated.
 *  	ALLOC_TYPE type	     : The type of deallocation being performed.
 */
void deAllocateMemory( void *address, ALLOC_TYPE type ) 
{
	// If the memory manager has not yet been initialized due to the order in which static
	// variables are allocated, create the memory manager here.
	if (!s_manager && !InitializeMemoryManager()) {
		free( address );   // Release the memory
		if (NumAllocations != 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -