资讯详情

VC开发非MFC程序内存泄漏跟踪代码

重写可执行模块源码new和delete函数,插入跟踪代码,在程序最终t退出前保存统计信息。以下代码基本上可以解决问题,但程序运行缓慢,可以作为测试来满足要求。

namespace foundation {  std::string MemleakNewDump()  {   DWORD id = ::GetCurrentThreadId();   HANDLE h = OpenThread(    THREAD_GET_CONTEXT,    TRUE,    id   ); //获得真实句柄    std::string strStack;    std::thread th([&] {    CONTEXT ctx = { 0 };    ctx.ContextFlags = CONTEXT_ALL;     ::SuspendThread(h);    ::GetThreadContext(h, &ctx);     MINIDUMP_EXCEPTION_INFORMATION eInfo;     EXCEPTION_POINTERS excpInfo;    excpInfo.ExceptionRecord = NULL;    excpInfo.ContextRecord = &ctx;     eInfo.ThreadId = GetCurrentThreadId();    eInfo.ExceptionPointers = &excpInfo;    eInfo.ClientPointers = FALSE;      strStack.clear();     // Initialize stack frame    STACKFRAME64 sf;    memset(&sf, 0, sizeof(STACKFRAME));  #if defined(_WIN64)    sf.AddrPC.Offset = ctx.Rip;    sf.AddrStack.Offset = ctx.Rsp;    sf.AddrFrame.Offset = ctx.Rbp; #elif defined(WIN32)    sf.AddrPC.Offset = ctx.Eip;    sf.AddrStack.Offset = ctx.Esp;    sf.AddrFrame.Offset = ctx.Ebp; #endif    sf.AddrPC.Mode = AddrModeFlat;    sf.AddrStack.Mode = AddrModeFlat;    sf.AddrFrame.Mode = AddrModeFlat;     DWORD _dwMachineType = 0;    char* chArchVar;    size_t requiredSize;    getenv_s(&requiredSize, NULL, 0, "PROCESSOR_ARCHITECTURE");    chArchVar = (char*)malloc(requiredSize * sizeof(char));    getenv_s(&requiredSize, chArchVar, requiredSize, "PROCESSOR_ARCHITECTURE");    if (chArchVar)    {     if ((!strcmp("EM64T", chArchVar)) || !strcmp("EM64T", chArchVar)) || !strcmp("AMD64", chArchVar))      _dwMachineType = IMAGE_FILE_MACHINE_AMD64;     else if (!strcmp("x86", chArchVar))      _dwMachineType = IMAGE_FILE_MACHINE_I386;    }     free(chArchVar);    if (0 == _dwMachineType)     return;     DWORD _dwCode = 0;    int _nTableCount = sizeof(g_ExceptDescTable) / sizeof(g_ExceptDescTable[0]);    bool _bFind = false;    for (int _i = 0; _i < _nTableCount;   _i)    {     if (_dwCode == g_ExceptDescTable[_i].dwCode)     {      strStack  = g_ExceptDescTable[_i].szDesc;      strStack  = "\r\n";      _bFind = true;      break;     }    }     char _sz[256];    if (!_bFind)    {     sprintf_s(_sz, "cxx except code: 0x%x\r\n", _dwCode);     strStack  = _sz;    }     // Walk through the stack frames.    HANDLE hProcess = GetCurrentProcess();    HANDLE hThread = GetCurrentThread();    if (!SymInitialize(hProcess, NULL, TRUE))    {     SymCleanup(hProcess);     return;    }     while (StackWalk64(_dwMachineType, hProcess, hThread, &sf, &ctx, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0))    {     if (sf.AddrFrame.Offset == 0)      break;      // 1. Get function name at the address     const int nBuffSize = (sizeof(SYMBOL_INFO)   MAX_SYM_NAME * sizeof(TCHAR)   sizeof(ULONG64) - 1) / sizeof(ULONG64);     ULONG64 symbolBuffer[nBuffSize];     PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;      pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);     pSymbol->MaxNameLen = MAX_SYM_NAME;      FunctionCall curCall;     curCall.FunctionName = "";     curCall.FileName = "";     curCall.LineNumber = 0;      DWORD64 dwSymDisplacement = 0;     if (SymFromAddr(hProcess, sf.AddrPC.Offset, &dwSymDisplacement, pSymbol))     {      curCall.FunctionName = pSymbol->Name;     }      //2. get line and file name at the address     IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };     DWORD dwLineDisplacement = 0;      if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))     {      curCall.FileName = (lineInfo.FileName);      curCall.LineNumber = lineInfo.LineNumber;     }      CStackDumper::_ATL_SYMBOL_INFO info;     sprintf_s(_sz, "6I64X: ", sf.AddrPC.Offset);     strStack  = _sz;     if (CStackDumper::ResolveSymbol(hProcess, UINT_PTR(sf.AddrPC.Offset), info))     {      strStack  = info.szModule;      strStack  = " ";      strStack  = info.szSymbol;      strStack  = "\r\n";     }     else      strStack  = "symbol not found";      strStack  = "File: ";     strStack  = curCall.FileName;     strStack  = "\r\n";     strStack  = "Func: ";     strStack  = curCall.FunctionName;     strStack  = "\r\n";     sprintf_s(_sz, "Line: %d", curCall.LineNumber);     strStack  = _sz;     strStack  = "\r\n\r\n";    }     SymCleanup(hProcess);    ::ResumeThread(h);    ::CloseHandle(h);   });    th.join();    return strStack;  }   struct myMap  {   const void* pData;   char* sz = NULL;   bool deleted = false;  };   static std::atomic<int> mmk = 0;  myMap* mmmap = NULL;;  std::mutex mtx;   HANDLE hProcess = NULL;  struct TWk  {   const void* block;   HANDLE h;  };   DWORD lastThreadID  = 0;  char strStack[8192 * 2] = { 0 };  bool inAlloc = true;  bool userCreateThreadEnvNotReady = true;   void allocStackString(HANDLE h, const void* block)  {   EnterCriticalSection(&csMemLeakDump);    strtack[0] = 0;
		CONTEXT ctx = { 0 };
		ctx.ContextFlags = CONTEXT_ALL;

		strStack[0] = 0;
		::SuspendThread(h);
		::GetThreadContext(h, &ctx);

		MINIDUMP_EXCEPTION_INFORMATION eInfo;

		EXCEPTION_POINTERS excpInfo;
		excpInfo.ExceptionRecord = NULL;
		excpInfo.ContextRecord = &ctx;

		eInfo.ThreadId = GetCurrentThreadId();
		eInfo.ExceptionPointers = &excpInfo;
		eInfo.ClientPointers = FALSE;

		// Initialize stack frame
		STACKFRAME64 sf;
		memset(&sf, 0, sizeof(STACKFRAME));

#if defined(_WIN64)
		sf.AddrPC.Offset = ctx.Rip;
		sf.AddrStack.Offset = ctx.Rsp;
		sf.AddrFrame.Offset = ctx.Rbp;
#elif defined(WIN32)
		sf.AddrPC.Offset = ctx.Eip;
		sf.AddrStack.Offset = ctx.Esp;
		sf.AddrFrame.Offset = ctx.Ebp;
#endif
		sf.AddrPC.Mode = AddrModeFlat;
		sf.AddrStack.Mode = AddrModeFlat;
		sf.AddrFrame.Mode = AddrModeFlat;

		DWORD _dwMachineType = 0;
		char* chArchVar;
		size_t requiredSize;
		getenv_s(&requiredSize, NULL, 0, "PROCESSOR_ARCHITECTURE");
		chArchVar = (char*)malloc(requiredSize * sizeof(char));
		getenv_s(&requiredSize, chArchVar, requiredSize, "PROCESSOR_ARCHITECTURE");
		if (chArchVar)
		{
			if ((!strcmp("EM64T", chArchVar)) || !strcmp("AMD64", chArchVar))
				_dwMachineType = IMAGE_FILE_MACHINE_AMD64;
			else if (!strcmp("x86", chArchVar))
				_dwMachineType = IMAGE_FILE_MACHINE_I386;
		}

		free(chArchVar);
		if (0 == _dwMachineType)
		{
			inAlloc = false;
			LeaveCriticalSection(&csMemLeakDump);
			if (-1 != ::ResumeThread(h))
				::CloseHandle(h);

			return;
		}

		char _sz[256];
		bool xmemory = false;
		if (!SymInitialize(hProcess, NULL, TRUE))
		{
			printf("%s", strStack);
			SymCleanup(hProcess);
			inAlloc = false;
			if (-1 != ::ResumeThread(h))
				::CloseHandle(h);
			LeaveCriticalSection(&csMemLeakDump);

			return;
		}

		while (StackWalk64(_dwMachineType, hProcess, h, &sf, &ctx, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0))
		{
			if (sf.AddrFrame.Offset == 0)
				break;

			// 1. Get function name at the address
			const int nBuffSize = (sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64);
			ULONG64 symbolBuffer[nBuffSize];
			PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;

			pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
			pSymbol->MaxNameLen = MAX_SYM_NAME;

			FunctionCall_2 curCall;
			strcpy(curCall.FunctionName, "");
			strcpy(curCall.FileName, "");
			curCall.LineNumber = 0;

			DWORD64 dwSymDisplacement = 0;
			if (SymFromAddr(hProcess, sf.AddrPC.Offset, &dwSymDisplacement, pSymbol))
			{
				strcpy(curCall.FunctionName, pSymbol->Name);
			}

			//2. get line and file name at the address
			IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };
			DWORD dwLineDisplacement = 0;

			if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))
			{
				strcpy(curCall.FileName, (lineInfo.FileName));
				curCall.LineNumber = lineInfo.LineNumber;
			}

			CStackDumper::_ATL_SYMBOL_INFO info;
			sprintf_s(_sz, "%016I64X: ", sf.AddrPC.Offset);
			strcat(strStack, _sz);
			if (CStackDumper::ResolveSymbol(hProcess, UINT_PTR(sf.AddrPC.Offset), info))
			{
				strcat(strStack, info.szModule);
				strcat(strStack, " ");
				strcat(strStack, info.szSymbol);
				strcat(strStack, "\r\n");
			}
			else
				strcat(strStack, "symbol not found");

			strcat(strStack, "File: ");
			strcat(strStack, curCall.FileName);
			int n = strlen(curCall.FileName);
			if (n >= 7)
			{
				char* p = curCall.FileName + n - 7;
				if (!strcmp(p, "xmemory")) //std::string  need this
					xmemory = true;
			}

			strcat(strStack, "\r\n");
			strcat(strStack, "Func: ");
			strcat(strStack, curCall.FunctionName);
			strcat(strStack, "\r\n");
			sprintf_s(_sz, "Line: %d", curCall.LineNumber);
			strcat(strStack, _sz);
			strcat(strStack, "\r\n\r\n");
		}

		if (mmk < 102400 * 4 - 2 && strStack[0] && !xmemory)
		{
			(mmmap + mmk)->pData = block;
			(mmmap + mmk)->deleted = false;
			(mmmap + mmk)->sz = (char*)malloc(strlen(strStack) + 4);
			strcpy((mmmap + mmk)->sz, strStack);
			mmk++;
		}

		SymCleanup(hProcess);
		if (-1 != ::ResumeThread(h))
			::CloseHandle(h);
		LeaveCriticalSection(&csMemLeakDump);

		inAlloc = false;
	}

	void MemleakNewDump(const void* block)
	{
		if (hProcess == NULL)
		{
			InitializeCriticalSection(&csMemLeakDump);
			InitializeCriticalSection(&csMemLeakFree);
		}

		hProcess = GetCurrentProcess();

		if (mmmap == NULL)
		{
			mmmap = (myMap*)malloc(102400 * 4 * sizeof(myMap));
			memset(mmmap, 0, 102400 * 4 * sizeof(myMap));
		}

		DWORD id = ::GetCurrentThreadId();
		if (lastThreadID == id)
			return;

		lastThreadID = id;
		HANDLE h = OpenThread(
			THREAD_GET_CONTEXT,
			TRUE,
			id
		); //获得真实句柄

		if (h == INVALID_HANDLE_VALUE)
			return;

		std::thread th([&] {
			allocStackString(h, block);
		});

		inAlloc = true;
		if (userCreateThreadEnvNotReady)
		{
			th.detach();
			int n = 20;
			while (inAlloc && n--)
				Sleep(60);

			if (n > 0)
				userCreateThreadEnvNotReady = false;
			else
				allocStackString(h, block);
		}
		else
			th.join();

		lastThreadID = 0;
	}

	void dumpMemLeak()
	{
		if (!mmmap)
			return;

		SYSTEMTIME st;
		GetLocalTime(&st);
		char sz[MAX_PATH + 4];
		sprintf(sz, "memLeak-%d-%02d-%02d=%02d-%02d-%02d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
		FILE* f = NULL;
		int cnt = 0;
		for (int i = 0; i < 102400 * 4 - 2; i++)
		{
			if (!(mmmap + i)->sz || (mmmap + i)->deleted)
				continue;

			printf("\n\n=============== %d =====================\n", ++cnt);
			printf("%s", (mmmap + i)->sz);

			if (f == NULL)
				f = fopen(sz, "w");

			fprintf(f, "\n\n=============== %d =====================\n", cnt);
			fprintf(f, "%s", (mmmap + i)->sz);
		}

		if (f != NULL)
			fclose(f);
	}

	void memLeakFree(void* db)
	{
		EnterCriticalSection(&csMemLeakFree);
		for (int i = 0; i < 102400 * 4 - 2; i++)
		{
			if (db == (mmmap + i)->pData)
			{
				(mmmap + i)->deleted = true;
				break;
			}
		}
		LeaveCriticalSection(&csMemLeakFree);
	}
};

//#define FOUNDATION_MEMLEAK_DETECT
void* __cdecl operator new(size_t const size)
{
	for (;;)
	{
		if (void* const block = malloc(size))
		{
#ifdef FOUNDATION_MEMLEAK_DETECT
			foundation::TriggerDump(block);
#endif
			return block;
		}

		if (_callnewh(size) == 0)
		{
			if (size == SIZE_MAX)
			{
				throw std::exception("bad alloc, SIZE_MAX");
			}
			else
			{
				throw std::exception("bad alloc");
			}
		}
	}
}

void __cdecl operator delete(void* p)
{
#if !defined(_ATL_NO_DEBUG_CRT) && defined(_DEBUG)
	_free_dbg(p, _NORMAL_BLOCK);
#else
	free(p);
#endif 
#ifdef FOUNDATION_MEMLEAK_DETECT
	foundation::memLeakFree(p);
#endif
}

标签: twk拉线式传感器swf

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台