📄 memorymanager.cpp
字号:
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 + -