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

📄 memorymanager.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 4 页
字号:
			log( "The Memory Manager has already been released from memory, however a deallocation was requested" );
		}
		return;
	}

	// The topStack contains the logged information, such as file name and line number.
	StackNode *info = s_manager->m_topStack.empty() ? NULL : s_manager->m_topStack.top();

	// Does the memory node exist within the hash table of the memory manager.
	MemoryNode *memory = s_manager->removeMemoryNode( address );

  
  if (!memory) {      // Validate that the memory was previously allocated.  If the memory was not logged 
		free( address );  // by the memory manager simple free the memory and return.  We do not log or 
    return;           // create any errors since we want the memory manager to be as seemless as possible.
	}

	// Log the memory deallocation if desired.
  if (s_manager->m_logAlways) {
		s_manager->log( "Memory Deallocation      : %-40s %8s(0x%08p) : %s", 
			              formatOwnerString( info->fileName, info->lineNumber ),
			              s_allocationTypes[type], address, memorySizeString( memory->reportedSize ) );
  }

  // 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 );

	// Validate that no memory errors occured.  If any errors have occured they will be written to the log 
	// file by the validateMemoryUnit() method.
  s_manager->validateMemoryUnit( memory );

  // Validate that there is not a allocation/deallocation mismatch
  m_assert( type == MM_DELETE       && memory->allocationType == MM_NEW       ||
            type == MM_DELETE_ARRAY && memory->allocationType == MM_NEW_ARRAY ||
            type == MM_FREE         && memory->allocationType == MM_MALLOC    ||
            type == MM_FREE         && memory->allocationType == MM_CALLOC    ||
            type == MM_FREE         && memory->allocationType == MM_REALLOC );

  // Validate that a break on deallocate was not set
  m_assert( (memory->options & BREAK_ON_DEALLOC) == 0x0 );

  // Free the memory
  free( memory->actualAddress );

  // Free the memory used to create the Memory Node
  s_manager->deallocateMemory( memory );

	// Free the info node used to hold the file and line number information for this deallocation.
	if (info) {
		s_manager->m_topStack.pop();
		free( info );
	}
}

/*******************************************************************************************/
/*******************************************************************************************/
// ***** Helper Functions

/*******************************************************************************************/
/*******************************************************************************************/
// ****** Implementation of the MemoryManager Class:

/**
 * MemoryManager::initialize():
 *  This method is responsible for initializing the Memory Manager.  
 * 
 *  Return Type : void 
 *  Arguments   : NONE
 */
void MemoryManager::initialize( void ) 
{
	m_breakOnAllocationCount = -1;
	m_paddingSize            = 4; 
	m_logAlways              = true;
	m_cleanLogFileOnFirstRun = true;  

	m_totalMemoryAllocated = m_totalMemoryUsed         = m_totalMemoryAllocations  = 0;
	m_peakMemoryAllocation = m_numAllocations          = m_peakTotalNumAllocations = 0;   
	m_overheadMemoryCost   = m_totalOverHeadMemoryCost = m_peakOverHeadMemoryCost  = 0;
	m_allocatedMemory      = m_numBoundsViolations     = 0;

	for (int ii = 0; ii < HASH_SIZE; ++ii) {
		m_hashTable[ii] = NULL;
	}

	m_topStack.init();

	m_memoryCache = NULL;
}

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

/**
 * MemoryManager::release():
 *  This method is responsible for releasing the Memory Manager.  It dumps the log file and 
 *  cleans up any memory that has been left behind.
 * 
 *  Return Type : void 
 *  Arguments   : NONE
 */
void MemoryManager::release( void )
{
	dumpLogReport();     // Dump the statistical information to the log file.

	// If there are memory leaks, be sure to clean up memory that the memory manager allocated.
	// It would really look bad if the memory manager created memory leaks!!!
	if (m_numAllocations != 0) {
		for (int ii = 0; ii < HASH_SIZE; ++ii) {
			while (m_hashTable[ii]) {
				MemoryNode *ptr = m_hashTable[ii];
				m_hashTable[ii] = m_hashTable[ii]->next;
				free( ptr->actualAddress );      // Free the memory left behind by the memory leak.
				free( ptr );                     // Free the memory used to create the Memory Node.
			}
		}
	}

	// Clean up the stack if it contains entries.
	while (!m_topStack.empty()) {
		free( m_topStack.top() );
		m_topStack.pop();
	}

	// Clean the memory cache
	MemoryNode *ptr;
	while (m_memoryCache) {
		ptr = m_memoryCache;
		m_memoryCache = ptr->next;
		free( ptr );
	}
}

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

/**
 * MemoryManager::insertMemoryNode():
 *  Inserts a memory node into the hash table and collects statistical information.
 * 
 *  Return Type : void 
 *  Arguments   : 
 *  	MemoryNode *node : The memory node to be inserted into the hash table.
 */
void MemoryManager::insertMemoryNode( MemoryNode *node )
{
	int hashIndex = getHashIndex( node->reportedAddress );
	node->next = m_hashTable[hashIndex];
	node->prev = NULL;

	if (m_hashTable[hashIndex]) m_hashTable[hashIndex]->prev = node;

	m_hashTable[hashIndex] = node;
	
	// Collect Statistic Information.
	m_numAllocations++;

	m_allocatedMemory += node->reportedSize;

	if (m_allocatedMemory > m_peakMemoryAllocation)   m_peakMemoryAllocation    = m_allocatedMemory;
	if (m_numAllocations > m_peakTotalNumAllocations) m_peakTotalNumAllocations = m_numAllocations;

	m_totalMemoryAllocated += node->reportedSize;
	m_totalMemoryAllocations++;
}

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

/**
 * MemoryManager::getMemoryNode():
 *  Returns the memory node for the given memory address, if the node does not exist a 
 *  NULL pointer is returned.
 * 
 *  Return Type : MemoryNode* -> A pointer to the requested memory node.
 *  Arguments   : 
 *  	void *address	: The address of the memory to be retrieved.
 */
MemoryNode* MemoryManager::getMemoryNode( void *address )
{
	MemoryNode *ptr = m_hashTable[getHashIndex( address )];
	while (ptr && ptr->reportedAddress != address) {
		ptr = ptr->next;
	}
	return ptr;
}

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

/**
 * MemoryManager::removeMemoryNode():
 *  Returns the memory node for the given memory address, if the node does not exist, a NULL
 *  pointer is returned.  This method also removes the memory node from the hash table.
 * 
 *  Return Type : MemoryNode* -> A pointer to the requested memory node.
 *  Arguments   : 
 *  	void *address	: The address of the memory to be retrieved.
 */
MemoryNode* MemoryManager::removeMemoryNode( void *address )
{
	int hashIndex = getHashIndex( address );
	
	if (hashIndex == 17) 
		int ttt = 0;
	
	MemoryNode *ptr = m_hashTable[hashIndex];
	while (ptr && ptr->reportedAddress != address) {
		ptr = ptr->next;
	}

	if (ptr) {
		if (ptr->next) ptr->next->prev = ptr->prev;
		if (ptr->prev) ptr->prev->next = ptr->next;
		else           m_hashTable[hashIndex] = ptr->next;

		// Update Statistical Information.
		m_numAllocations--;
		m_allocatedMemory -= ptr->reportedSize;
	}
	return ptr;
}

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

/**
 * MemoryManager::validateMemoryUnit():
 *  Given a Memory Node, this method will interrogate its memory looking for bounds violations
 *  and the number of bytes that were actually used.  This method should only be called before
 *  deleting a Memory Node to generate statistical information.  This method will report all 
 *  errors to the log file.  Returns TRUE if no bounds violations where found, otherwise FALSE.
 * 
 *  Return Type : bool -> True if no bounds violations, otherwise False.
 *  Arguments   : 
 *  	MemoryNode *node : The memory node to be interrogated.
 */
bool MemoryManager::validateMemoryUnit( MemoryNode *node )
{
	bool success = true;
	unsigned int ii;
	unsigned int totalBytesUsed = 0, boundViolations = 0;

	// Detect bounds violations
	long *beginning = (long*)node->actualAddress;
	long *ending    = (long*)((char*)node->actualAddress + node->actualSize - node->paddingSize*sizeof(long));
	for (ii = 0; ii < node->paddingSize; ++ii) {
		if (beginning[ii] != PADDING || ending[ii]!= PADDING) {
			success = false;  // Report the bounds violation.
			boundViolations++;
		}
	}

	if (!success) m_numBoundsViolations++;

	// Attempt to determine how much of the allocated memory was actually used.
	// Initialize the memory padding for detecting bounds violations.
	long *lptr       = (long*)node->reportedAddress;
	unsigned int len = node->reportedSize / sizeof(long);
	unsigned int cnt;
	for (cnt = 0; cnt < len; ++cnt) {                        
		if (lptr[cnt] != node->predefinedBody)       totalBytesUsed += sizeof(long);
	}
	char *cptr = (char*)(&lptr[cnt]);
	len = node->reportedSize - len*sizeof(long);
	for (cnt = 0; cnt < len; ++cnt) {    
		if (cptr[cnt] != (char)node->predefinedBody) totalBytesUsed++;
	}

	m_totalMemoryUsed += totalBytesUsed;

	if (m_logAlways && totalBytesUsed != node->reportedSize) {          // Report the percentage 
		this->log( "Unused Memory Detected   : %-40s %8s(0x%08p) : %s",   //  of waisted memory space.
			         formatOwnerString( node->sourceFile, node->sourceLine ),
			         s_allocationTypes[node->allocationType], node->reportedAddress, 
							 memorySizeString( node->reportedSize - totalBytesUsed ) );
	}

	if (m_logAlways && !success) {                                      // Report the memory 
		this->log( "Bounds Violation Detected: %-40s %8s(0x%08p)",        //  bounds violation.
			         formatOwnerString( node->sourceFile, node->sourceLine ),
			         s_allocationTypes[node->allocationType], node->reportedAddress );
	}

	return success;
}

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

/**
 * MemoryManager::deallocateMemory():
 *  This method adds the MemoryNode to the memory cache for latter use.
 * 
 *  Return Type : void 
 *  Arguments   : 
 *  	MemoryNode *node : The MemoryNode to be released.
 */
void MemoryManager::deallocateMemory( MemoryNode *node )
{
	m_overheadMemoryCost -= (node->paddingSize * 2 * sizeof(long));
	node->next = m_memoryCache;
	m_memoryCache = node;
}

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

/**
 * MemoryManager::allocateMemory():
 *  This method checks the memory cache for unused MemoryNodes, if one exists it is removed
 *  from the cache and returned.  Otherwise, new memory is allocated for the MemoryNode and
 *  returned.
 * 
 *  Return Type : MemoryNode* -> The allocated MemoryNode.
 *  Arguments   : NONE
 */
MemoryNode* MemoryManager::allocateMemory( void )
{
	if (!m_memoryCache) {
		int overhead = m_paddingSize * 2 * sizeof(long) + sizeof( MemoryNode );
		m_overheadMemoryCost += overhead;
		m_totalOverHeadMemoryCost += overhead;

		if (m_overheadMemoryCost > m_peakOverHeadMemoryCost) {
			m_peakOverHeadMemoryCost =  m_overheadMemoryCost;

⌨️ 快捷键说明

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