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

📄 memrecord.cpp

📁 linux下的垃圾收集
💻 CPP
字号:
#include "MemRecord.h"MemRecord appMemory;#if defined( MEM_DEBUG )char DELETE_FILE[ FILENAME_LENGTH ] = {0};int DELETE_LINE = 0;CCommonMutex globalLock;stack<DELINFOSTACK> globalStack;void BuildStack(){	DELINFOSTACK stDis = {"",0};	strcpy(stDis.Filename, DELETE_FILE);	stDis.LineNum = DELETE_LINE;	globalStack.push(stDis);}void* operator new( size_t nSize, char* pszFileName, int nLineNum ){	MemOperation record;	void *pResult;		pResult = ::operator new( nSize );		if ( pResult )	{		// record the alloc memory		strncpy( record.Filename, pszFileName, FILENAME_LENGTH - 1 );		record.Filename[ FILENAME_LENGTH - 1 ] = '\0';		record.LineNum = nLineNum;		record.AllocSize = nSize;		record.OperationType = SINGLE_NEW;		record.errCode = 0;		record.pBuffer = pResult;		appMemory.Insert( pResult, &record );	}		return pResult;}void* operator new[]( size_t nSize, char* pszFileName, int nLineNum ){	MemOperation record;	void *pResult;		pResult = ::operator new[]( nSize );		if ( pResult )	{		// record the alloc memory		strncpy( record.Filename, pszFileName, FILENAME_LENGTH - 1 );		record.Filename[ FILENAME_LENGTH - 1 ] = '\0';		record.LineNum = nLineNum;		record.AllocSize = nSize;		record.OperationType = ARRAY_NEW;		record.errCode = 0;		record.pBuffer = pResult;		appMemory.Insert( pResult, &record );	}	return pResult;}void operator delete( void *ptr ){	if ( NULL == ptr )	{		globalLock.Unlock();		return;	}			MemOperation record;	strncpy( record.Filename, DELETE_FILE, FILENAME_LENGTH - 1 );	record.Filename[ FILENAME_LENGTH - 1 ] = '\0';	record.LineNum = DELETE_LINE;	record.AllocSize = 0; // Unknown, but compiler known	record.OperationType = SINGLE_DELETE;	record.errCode = 0;	record.pBuffer = ptr;	strcpy( DELETE_FILE , "" );	DELETE_LINE = 0 ;		globalLock.Unlock();	appMemory.Erase( ptr, &record );	free( ptr );}voidoperator delete[]( void *ptr ){	if ( NULL == ptr )	{		globalLock.Unlock();		return;	}		MemOperation record;	strncpy( record.Filename, DELETE_FILE, FILENAME_LENGTH - 1 );	record.Filename[ FILENAME_LENGTH - 1 ] = '\0';	record.LineNum = DELETE_LINE;	record.AllocSize = 0; // Unknown, but compiler known	record.OperationType = ARRAY_DELETE;	record.errCode = 0;	record.pBuffer = ptr;	strcpy( DELETE_FILE , "" );	DELETE_LINE = 0 ;	globalLock.Unlock();		appMemory.Erase( ptr, &record );	free( ptr );}static void interruptHandler( int signo );void DecodeErr( int ErrNum );static void interruptHandler( int signo ){	char msgPath[ 128 ];		appMemory.GetMsgFilePath( msgPath );/*	switch( signo )	{	case SIGINT: printf( "SIGINT" ); break;	case SIGQUIT: printf( "SIGQUIT" ); break;	case SIGABRT: printf( "SIGABRT" ); break;	case SIGKILL: printf( "SIGKILL" ); break;	case SIGSEGV: printf( "SIGSEGV" ); break;	default: printf( "SIGNO = %d", signo ); break;	}	printf( " 信号, 将删除消息队列\n" );	printf( "正在删除消息队列, 稍等......\n" );*/	int nRtn = msgctl( appMemory.GetMsgQueue(), IPC_RMID, NULL ); // delete the message queue	if (nRtn == -1)	{/*		switch( errno )		{		case EAGAIN: printf( "---EAGAIN---\n" ); break;		case EACCES: printf( "---EACCES---\n" ); break;		case EFAULT: printf( "---EFAULT---\n" ); break;		case EIDRM:  printf( "---EIDRM---\n" );  break;		case EINTR:  printf( "---EINTR---\n" );  break;		case EINVAL: printf( "---EINVAL---\n" ); break;		case ENOMEM: printf( "---ENOMEM---\n" ); break;		default: printf( "---Undefined---\n" );  break;			}*/			printf("MemRecord Cleaner: Sorry, I am failed to delete the MSG QUEUE. please use ipcrm to delete msgqueue %d.\r\n", appMemory.GetMsgQueue());	}//	printf( "成功删除消息队列\n" );//	printf( "正在删除文件\"%s\", 稍等......\n", msgPath );	nRtn = unlink( msgPath );//	if ( 0 == nRtn )//		printf( "删除文件\"%s\"成功\n", msgPath );	exit( 1 );}void DecodeErr( int ErrNum ){	switch( ErrNum )	{	case EAGAIN:		printf( "---EAGAIN---\n" );		break;	case EACCES:		printf( "---EACCES---\n" );		break;	case EFAULT:		printf( "---EFAULT---\n" );		break;	case EIDRM:		printf( "---EIDRM---\n" );		break;	case EINTR:		printf( "---EINTR---\n" );		break;	case EINVAL:		printf( "---EINVAL---\n" );		break;	case ENOMEM:		printf( "---ENOMEM---\n" );		break;	default:		printf( "---Undefined---\n" );		break;		}}MemRecord::MemRecord(){		m_pidMain = getpid();		/**	 * create a message queue if the message not exist, else delete the	 * existed message queue first and then create it.	 */	key_t key;	int flags, counter = 0;	struct passwd *pwd;	FILE *fp = NULL;//	m_pidChild = -1 ;		// POSIX函数, getpwend()在POSIX中没有定义(svr4中定义了)故这里没有使用getpwent()	// 取得运行该进程的用户的缺省目录	if ( NULL == (pwd = getpwuid( getuid() ) ) )	{		printf( "MemRecord : Failed to get current users information.\r\n" );		exit( 1 );	}	sprintf( m_szMsgPath, "%s/.MemMsgQueue%d", pwd->pw_dir, m_pidMain );		// 确保m_szMsgPath表示的文件存在, 否则计算创建消息队列成功	// 其key值也将是0XFFFFFFFF(-1)。	// 如果文件不存在则创建, 创建不成功则尝试10次	do	{		// Open for reading and appending (writing at end  of  file). The		// file  is created if it does not exist		fp = fopen( m_szMsgPath, "a+" );		if ( fp )			break;	} while( counter++ < 10 );	if ( NULL == fp )	{		printf( "MemRecord : Cannot create symbol file for Msg queue: %s\n", m_szMsgPath );		exit( 1 );	}	key  =  ftok( m_szMsgPath, 'a' );	if ( -1 == key )	{				printf( "MemRecord : Cannot Create KEY for MemRecord Message queue.\r\n" );		exit( 1 );	}	/**	 * use msgget with IPC_CREATE param to get the message queue id	 * if the mesasge queue exist, else create it.	 */	m_nMsgQueue  =  msgget( key, IPC_CREAT );	if( m_nMsgQueue != -1 ) // the message queue exist then delete it	{		// delete the message queue		if ( msgctl( m_nMsgQueue, IPC_RMID, NULL ) == -1 )		{			printf( "MemRecord : Cannot Delete the old Message queue, please delete them with ipcrm and retry.\r\n" );			exit( 1 ); 	// need modify because the failure of delete 				 	// message queue cannot exit the system		}	}	/**	 * the code below guarantee that the message queue with "key" value	 * must be delete whether exist.	 *	 * create the message queue again with "key" value	 */	flags  =  IPC_CREAT | IPC_EXCL | 0666;	m_nMsgQueue = msgget( key, flags );	if ( m_nMsgQueue == -1 )	{		printf( "MemRecord : Cannot create the Message Queue.\r\n" );		exit( 1 );	}	///////////////////////////////////////////////////////////////////////////	// 启动一个孤儿进程来监视被监控进程的情况,如被监控进程退出,则清除所创建的文件标识和消息队列	pid_t  pidChild;	if ( ( pidChild = fork() ) < 0 )	{		printf( "MemRecord : Failed to Create ChildProcess which is used to do cleanup.\r\n" );		exit( 1 );		}	else if ( 0 == pidChild )	{		pid_t pidGrandson = fork();		if (pidGrandson < 0)		{			printf( "MemRecord : Failed to Create ChildProcess which is used to do cleanup.\r\n" );			exit( 1 );						}		else if (pidGrandson == 0)		{			char buf1[32] = {0};			char buf2[32] = {0};			char buf3[32] = {0};			char buf4[128] = {0};						strcpy(buf1, "./MemCleaner");			sprintf(buf2, "%d",appMemory.GetMainProcessPid());			sprintf(buf3, "%d",appMemory.GetMsgQueue());			appMemory.GetMsgFilePath( buf4 ); 									execlp("./MemCleaner", buf1, buf2, buf3, buf4, 0);		}		else		{			exit(0);		}	}	else	{		int status;		wait(&status);	}	///////////////////////////////////////////////////////////////////////////}MemRecord::~MemRecord(){	if (!m_mapMemory.empty() || !m_listMemory.empty())	{		printf("MemRecord : We think there's some memory leak happened, please check the leak.rec file for detail.\r\n");		// Truncate  file  to  zero  length or create text file for writing		FILE *fp = fopen( "leak.rec", "w" ); 		if ( NULL == fp ) // if fail to open the file, assignment stdout to it		{			fp = stdout;		}				fprintf( fp, "Memory leak %d times, description as below:\n\n",			m_mapMemory.size() + m_listMemory.size() );		fprintf( fp, "%-24s%-16s%-16s%-16s%-8s%s\n",			"FILE NAME", "LINE NUMBER", "MEMORY SIZE",			"POINTER", "ALLOC", "LEAK REASON" );		fprintf( fp, "------------------------------------------------"			"------------------------------------------------\n" );				// print the content of m_mapMemory and m_listMemory to leak.rec file		map<void *, MemOperation>::iterator mapIterator = m_mapMemory.begin();		char *types[2] = { "new", "new[]" };		char *err[2] = { "not free", "use delete" };				// output the content of m_mapMemory to file		while( mapIterator != m_mapMemory.end() )		{			fprintf( fp, "%-24s%-16d%-16d%-#16X%-8s%s\n",				 mapIterator->second.Filename, mapIterator->second.LineNum,				 mapIterator->second.AllocSize, 				 mapIterator->second.pBuffer,				 types[ mapIterator->second.OperationType % 2 ],				 err[ mapIterator->second.errCode ] );			fflush( fp );			mapIterator++;		}		list<MemOperation>::iterator record;		// output the content of m_listMemory to file		for ( record = m_listMemory.begin(); record != m_listMemory.end(); record++ )		{			fprintf( fp, "%-24s%-16d%-16d%-#16X%-8s%s\n",				 record->Filename, record->LineNum,				 record->AllocSize,				 record->pBuffer,				 types[ record->OperationType % 2 ],				 err[ record->errCode ] );			fflush( fp );		}		fprintf( fp, "------------------------------------------------"			"------------------------------------------------\n" );	}//	int rc = msgctl( m_nMsgQueue, IPC_RMID, NULL ); // delete the message queue//	char cmd[64];//	if ( 0 != rc ) printf("MemRecord : Sorry, I am failed to delete the MSG QUEUE. please use ipcrm to delete msgqueue %d.\r\n", appMemory.GetMsgQueue());//	unlink( m_szMsgPath );//	m_mutexRecord.Unlock();//	sprintf( cmd, "kill -9 %d", m_pidChild );//	// 当程序正常结束的时候将子进程杀掉, 不然子进程将会变为孤儿//	system( cmd ); 	}voidMemRecord::Insert( void *pBuffer, MemOperation *pRecord ){	MemOperation record;	MsgBuffer SendMsg;	static bool firstError = true;	if ( !pBuffer || !pRecord )	{		return;	}	m_mutexRecord.Lock();	// insert to the new/new[] operation to member data m_mapMemory	memcpy( ( void * ) &record, pRecord, sizeof( MemOperation ) );	pair<void *, MemOperation> value(pBuffer, record);		if ( m_nMsgQueue != -1 ) // send a message to message queue if the message queue available	{		int rc;		struct msqid_ds	msgInfo;				if ( 0 == msgctl( m_nMsgQueue, IPC_STAT, &msgInfo ) )		{			if ( msgInfo.msg_qbytes > ( msgInfo.msg_cbytes + sizeof( MemOperation ) + 4 ) )			{				memcpy( ( void * ) &SendMsg.Data, pRecord, sizeof( MemOperation ) );				SendMsg.Data.errCode = 0; // indicate new operation, it is use for message queue only				SendMsg.Type = MEMORY_INFO;				rc = msgsnd( m_nMsgQueue, &SendMsg, sizeof( SendMsg.Data ), IPC_NOWAIT );				if ( rc == -1 ) // fail to send				{					//DecodeErr( errno );					printf( "MemRecord : Error when try to send data from Message queue.\r\n" ); 				}				else					firstError = true;			}		}		else		{			if ( firstError )			{				//DecodeErr( errno );				//printf( "在检查消息队列的属性时出错\n" );				firstError = false;			}		}	}	m_mapMemory.insert( value );	m_mutexRecord.Unlock();}intMemRecord::Erase( void *pBuffer, MemOperation *pRecord ){	map<void *, MemOperation>::iterator record;	MsgBuffer SendMsg;	static bool firstError = true;	if ( !pBuffer || !pRecord )		{		return -1;	}	if((!strcmp(pRecord->Filename,""))&&(pRecord->LineNum == 0))	{		record = m_mapMemory.find( pBuffer );		// if the global delete info is empty and cannot find this		// pointer in our map, that mean the pointer of this delete request		// is not "new" by us. so just drop it		if ( record == m_mapMemory.end() )		{			return -1;		}		// if we can find the pointer in our map but the global delete info		// is zero, it maybe a "recursion(递归) delete", so if stack isn't empty we will		// pop the corresponding delete info in the stack and go on.		if (!globalStack.empty())		{			DELINFOSTACK stDis = globalStack.top();						strcpy(pRecord->Filename, stDis.Filename);			pRecord->LineNum = stDis.LineNum;						globalStack.pop();		}	}	m_mutexRecord.Lock();		if ( m_nMsgQueue != -1 ) // send a message to message queue if the message queue available	{		int rc;		struct msqid_ds	msgInfo;				// 取得消息队列的属性		rc = msgctl( m_nMsgQueue, IPC_STAT, &msgInfo );		if ( 0 == rc )		{			//  判断消息队列是否还有空间可用			if ( msgInfo.msg_qbytes > ( msgInfo.msg_cbytes + sizeof( MemOperation ) + 4 ) )			{				memcpy( ( void * ) &SendMsg.Data, pRecord, sizeof( MemOperation ) );				SendMsg.Data.errCode = 1;				SendMsg.Type = MEMORY_INFO;				rc = msgsnd( m_nMsgQueue, &SendMsg, sizeof( SendMsg.Data ), IPC_NOWAIT );				if ( rc == -1 ) // 如果出错则给出相应的提示				{					//DecodeErr( errno );					printf( "MemRecord : Error when try to send data from Message queue.\r\n" ); 				}				else					firstError = true;			}		}		else		{			if ( firstError )			{				//DecodeErr( errno );				//printf( "在检查消息队列的属性时出错\n" );				firstError = false;			}		}	}	record = m_mapMemory.find( pBuffer );	if ( record != m_mapMemory.end() )	{				bool bError = 			( SINGLE_DELETE == pRecord->OperationType ) && ( ARRAY_NEW == record->second.OperationType );		MemOperation temp;				if ( bError ) // error if alloc with new[] type and free with delete type		{			memcpy( &temp, &( record->second ), sizeof( MemOperation ) );			temp.errCode = 1;			m_listMemory.push_back( temp );		}				m_mapMemory.erase( record );		m_mutexRecord.Unlock();		return 0;	}	else	{				// delete a  memory pointer that no-existed or alloc with new[] type		// it will cause the uncertain result, so I will give a warning message on screen		printf( "MemRecord : *****WARNING: At %s line %ld -- %#x, You delete a pointer that cannot find in MAP.******\n",			pRecord->Filename, pRecord->LineNum , pBuffer);		m_mutexRecord.Unlock();				return -2;			}}voidMemRecord::GetMsgFilePath( char *path ){	if ( NULL == path )		return;	strcpy( path, m_szMsgPath );	return;}#endif                                                    

⌨️ 快捷键说明

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