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

📄 memorymanager.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 4 页
字号:
		}

		return (MemoryNode*)malloc( sizeof(MemoryNode) );
	}
	else {
		int overhead = m_paddingSize * 2 * sizeof(long);
		m_overheadMemoryCost += overhead;
		m_totalOverHeadMemoryCost += overhead;

		if (m_overheadMemoryCost > m_peakOverHeadMemoryCost) {
			m_peakOverHeadMemoryCost =  m_overheadMemoryCost;
		}

		MemoryNode *ptr = m_memoryCache;
		m_memoryCache = m_memoryCache->next;
		return ptr;
	}
}

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

/**
 * MemoryManager::dumpLogReport():
 *  This method implements the main reporting system.  It reports all of the statistical
 *  information to the desired log file.
 * 
 *  Return Type : void 
 *  Arguments   : NONE
 */
void MemoryManager::dumpLogReport( void )
{
	if (m_cleanLogFileOnFirstRun) {      // Cleanup the log?
		unlink( LOGFILE );                 // Delete the existing log file.
		m_cleanLogFileOnFirstRun = false;  // Toggle the flag.
	}

	FILE	*fp = fopen( LOGFILE, "ab" ); // Open the log file
	if (!fp) return;

  time_t t = time( NULL );
  tm *time = localtime( &t );
	
	int memoryLeak = calculateUnAllocatedMemory();
	int totalMemoryDivider = m_totalMemoryAllocated != 0 ? m_totalMemoryAllocated : 1;

	// Header Information
	fprintf( fp, "\r\n" );
	fprintf( fp, "******************************************************************************* \r\n");
  fprintf( fp, "*********           Memory report for: %02d/%02d/%04d %02d:%02d:%02d            ********* \r\n", time->tm_mon + 1, time->tm_mday, time->tm_year + 1900, time->tm_hour, time->tm_min, time->tm_sec );
	fprintf( fp, "******************************************************************************* \r\n");
	fprintf( fp, "\r\n" );

	// Report summary
	fprintf( fp, "                     T O T A L  M E M O R Y  U S A G E                          \r\n" );
	fprintf( fp, "------------------------------------------------------------------------------- \r\n" );
	fprintf( fp, "           Total Number of Dynamic Allocations: %10s\r\n", insertCommas( m_totalMemoryAllocations ) );
	fprintf( fp, "      Reported Memory usage to the Application: %s\r\n", memorySizeString( m_totalMemoryAllocated ) );
	fprintf( fp, "          Actual Memory use by the Application: %s\r\n", memorySizeString( m_totalOverHeadMemoryCost + m_totalMemoryAllocated ) );
	fprintf( fp, "                      Memory Tracking Overhead: %s\r\n", memorySizeString( m_totalOverHeadMemoryCost ) );
	fprintf( fp, "\r\n");

	fprintf( fp, "                      P E A K  M E M O R Y  U S A G E                           \r\n");
	fprintf( fp, "------------------------------------------------------------------------------- \r\n");
	fprintf( fp, "            Peak Number of Dynamic Allocations: %10s\r\n", insertCommas( m_peakTotalNumAllocations ) );
	fprintf( fp, " Peak Reported Memory usage to the application: %s\r\n", memorySizeString( m_peakMemoryAllocation ) );
	fprintf( fp, "     Peak Actual Memory use by the Application: %s\r\n", memorySizeString( m_peakOverHeadMemoryCost + m_peakMemoryAllocation ) );
	fprintf( fp, "                 Peak Memory Tracking Overhead: %s\r\n", memorySizeString( m_peakOverHeadMemoryCost ) );
	fprintf( fp, "\r\n");

	fprintf( fp, "                          U N U S E D  M E M O R Y                              \r\n");
	fprintf( fp, "------------------------------------------------------------------------------- \r\n");
	fprintf( fp, "  Percentage of Allocated Memory Actually Used: %10.2f %%\r\n", (float)(1 - (m_totalMemoryAllocated - m_totalMemoryUsed)/(float)totalMemoryDivider) * 100 );
	fprintf( fp, "       Percentage of Allocated Memory Not Used: %10.2f %%\r\n", (float)(m_totalMemoryAllocated - m_totalMemoryUsed)/(float)totalMemoryDivider * 100 );
	fprintf( fp, "        Memory Allocated but not Actually Used: %s\r\n", memorySizeString( m_totalMemoryAllocated - m_totalMemoryUsed ) );
	fprintf( fp, "\r\n");

	fprintf( fp, "                      B O U N D S  V I O L A T I O N S                          \r\n");
	fprintf( fp, "------------------------------------------------------------------------------- \r\n");
	fprintf( fp, "            Number of Memory Bounds Violations: %10s\r\n", insertCommas( m_numBoundsViolations ) );
	fprintf( fp, "\r\n");

	fprintf( fp, "                           M E M O R Y  L E A K S                               \r\n");
	fprintf( fp, "------------------------------------------------------------------------------- \r\n");
	fprintf( fp, "                        Number of Memory Leaks: %10s\r\n", insertCommas( m_numAllocations ) );
	fprintf( fp, "                 Amount of Memory Un-Allocated: %s\r\n", memorySizeString( memoryLeak ) );
	fprintf( fp, "   Percentage of Allocated Memory Un-Allocated: %10.2f %%\r\n", (float)(1 - (m_totalMemoryAllocated - memoryLeak)/(float)totalMemoryDivider) * 100 );
	fprintf( fp, "\r\n");

	if (m_numAllocations != 0) {  // Are there memory leaks?
		fclose( fp );               // Close the log file.
		dumpMemoryAllocations();    // Display any memory leaks.
	}
	else {
		fclose( fp );
	}
}

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

/**
 * MemoryManager::dumpMemoryAllocations():
 *  This method is responsible for reporting all memory that is currently allocated.  This is
 *  achieved by reporting all memory that is still within the hash table.  
 * 
 *  Return Type : void 
 *  Arguments   : NONE
 */
void MemoryManager::dumpMemoryAllocations( void )
{
	if (m_cleanLogFileOnFirstRun) {      // Cleanup the log?
		unlink( LOGFILE );                 // Delete the existing log file.
		m_cleanLogFileOnFirstRun = false;  // Toggle the flag.
	}

	FILE	*fp = fopen( LOGFILE, "ab" ); // Open the log file
	if (!fp) return;

	fprintf( fp, "              C U R R E N T L Y  A L L O C A T E D  M E M O R Y                 \r\n" );
	fprintf( fp, "------------------------------------------------------------------------------- \r\n" );

	for (int ii = 0, cnt = 1; ii < HASH_SIZE; ++ii) {
		for (MemoryNode *ptr = m_hashTable[ii]; ptr; ptr = ptr->next) {
			fprintf( fp, "** Allocation # %2d\r\n", cnt++ );
			fprintf( fp, "Total Memory Size : %s\r\n", memorySizeString( ptr->reportedSize, false ) );
			fprintf( fp, "Source File       : %s\r\n", ptr->sourceFile );
			fprintf( fp, "Source Line       : %d\r\n", ptr->sourceLine );
			fprintf( fp, "Allocation Type   : %s\r\n", s_allocationTypes[ptr->allocationType] );
			fprintf( fp, "\r\n");
		}
	}

	fprintf( fp, "------------------------------------------------------------------------------- \r\n" );
	fprintf( fp, "******************************************************************************* \r\n" );
	fprintf( fp, "\r\n" );

	fclose( fp );
}

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

/**
 * MemoryManager::log():
 *  Dumps a specific string to the log file.  Used for error reporting during runtime.  This
 *  method accepts a variable argument lenght such as printf() for ease of reporting.
 * 
 *  Return Type : void 
 *  Arguments   : 
 *  	char *s	: The string to be written to the log file.
 *  	...	    : The parameters to be placed within the string, simular to say: printf( s, ... )
 */
void MemoryManager::log( char *s, ... )
{
	if (m_cleanLogFileOnFirstRun) {      // Cleanup the log?
		unlink( LOGFILE );                 // Delete the existing log file.
		m_cleanLogFileOnFirstRun = false;  // Toggle the flag.
	}

	static char buffer[2048];    // Create the buffer
	va_list	list;                // Replace the strings variable arguments with the provided
	va_start( list, s );         //  arguments.
	vsprintf( buffer, s, list );
	va_end( list );

	FILE	*fp = fopen( LOGFILE, "ab" );  // Open the log file
	if (!fp) return;

	fprintf( fp, "%s\r\n", buffer );     // Write the data to the log file
	fclose( fp );                        // Close the file
}

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

/**
 * MemoryManager::getHashIndex():
 *  Returns the hash index for the given memory address.
 * 
 *  Return Type : int -> The hash table index.
 *  Arguments   : 
 *  	void *address	: The address to determine the hash table index for.
 */
int MemoryManager::getHashIndex( void *address )
{
	return ((unsigned int)address >> 4) & (HASH_SIZE -1);
}

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

/**
 * MemoryManager::calculateUnAllocatedMemory():
 *  Returns the amount of unallocated memory in BYTES.
 * 
 *  Return Type : int -> The number of BYTES of unallocated memory.
 *  Arguments   : NONE
 */
int MemoryManager::calculateUnAllocatedMemory( void )
{
	int memory = 0;
	for (int ii = 0; ii < HASH_SIZE; ++ii) {
		for (MemoryNode *ptr = m_hashTable[ii]; ptr; ptr = ptr->next) {
			memory += ptr->reportedSize;
		}
	}
	return memory;
}


/*******************************************************************************************/
/*******************************************************************************************/
// ****** Implementation of the MemoryNode Struct

/**
 * MemoryNode::InitializeMemory():
 *  Initialize the padding and the body of the allocated memory so that it can be interrogated
 *  upon deallocation.
 * 
 *  Return Type : void 
 *  Arguments   : 
 *  	long body	: The value to which the body of the allocated memory should be intialized too.
 */
void MemoryNode::InitializeMemory( long body ) 
{
	// Initialize the memory padding for detecting bounds violations.
	long *beginning = (long*)actualAddress;
	long *ending    = (long*)((char*)actualAddress + actualSize - paddingSize*sizeof(long));
	for (unsigned short ii = 0; ii < paddingSize; ++ii) {
		beginning[ii] = ending[ii] = PADDING;
	}

	// Initialize the memory body for detecting unused memory.
	beginning        = (long*)reportedAddress;
	unsigned int len = reportedSize / sizeof(long);
	unsigned int cnt;
	for (cnt = 0; cnt < len; ++cnt) {                         // Initialize the majority of the memory
		beginning[cnt] = body;
	}
	char *cptr = (char*)(&beginning[cnt]);
	len = reportedSize - len*sizeof(long);
	for (cnt = 0; cnt < len; ++cnt) {    // Initialize the remaining memory
		cptr[cnt] = (char)body;
	}

	predefinedBody = body;
}


/*******************************************************************************************/
/*******************************************************************************************/
// ****** Implementation of the Initialize Class

/**
 * Initialize::Initialize():
 *  Initialize the Memory Manager Object.  This class is required to ensure that the Memory
 *  Manager has been created before dynamic allocation occure within other statically 
 *  allocated objects.
 * 
 *  Return Type : 
 *  Arguments   : NONE
 */
Initialize::Initialize( void )
{
	InitializeMemoryManager();  // Create the Memory Manager Object.
}


/*******************************************************************************************/
/*******************************************************************************************/
// ****** Implementation of Helper Functions

/**
 * InitializeMemoryManager():
 *  This method is responsible for creating a Memory Manager Object.  If the object already
 *  exists or is successfully created TRUE is returned.  Otherwise if the object was 
 *  previously created and has been destroyed FALSE is returned.  The goal is to guarantee
 *  that the Memory Manager is the first object to be created and the last to be destroyed.
 * 
 *  Return Type : bool -> True if intialized, otherwise False.
 *  Arguments   : NONE
 */
bool InitializeMemoryManager( void )
{
	static bool hasBeenInitialized = false;

	if (s_manager) {                     // The memory manager object already exists.
		return true;
	}
	else if (hasBeenInitialized) {       // The memory manager object has already been created
		return false;                      //    once, however it was release before everyone 
	}                                    //    was done.
	else {                               // Create the memory manager object.
		s_manager = (MemoryManager*)malloc( sizeof(MemoryManager) );
		s_manager->initialize();
		atexit( releaseMemoryManager );    // Log this function to be called upon program shut down.
		hasBeenInitialized = true;
		return true;
	}
}

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

/**
 * releaseMemoryManager():
 *  This method is automatically called when the application is terminated.  It is important
 *  that this is the last function called to perform application cleanup since the memory 
 *  manager object should be the last object to be destoryed, thus this must be the first 
 *  method logged to perform application clean up.
 * 
 *  Return Type : void 
 *  Arguments   : NONE
 */
void releaseMemoryManager( void ) 
{
	NumAllocations = s_manager->m_numAllocations;
	s_manager->release();  // Dump the log report and free remaining memory.
	free( s_manager );
	s_manager = NULL;
}

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

/**
 * formatOwnerString():

⌨️ 快捷键说明

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