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