我一直在调整this code(c ++版本)以满足我的需求,这需要运行很长的视频序列。几百帧后,程序因内存问题而崩溃。如果我检查进程使用的内存,它使用超过1.6 GB的RAM。检查内存使用情况(使用Windows任务管理器以非常愚蠢的方式..)我注意到每个帧都使用了相同数量的额外内存。
我被告知使用MS Visual Studio(我目前正在使用的IDE)我应该能够在某个时刻看到哪些变量正在使用更多内存,以便找到哪一个导致了内存泄漏并修复它,但我在IDE中找不到任何相关内容。
如果可能,我不想使用像Valgrind这样的工具并使用Visual Studio解决问题。如果不是......那么,当我到达那里时,我会想到这一点:)
谢谢!
答案 0 :(得分:2)
我发现微软的UMDH(“用户模式转储堆”)工具一次又一次地救了我。您可以找到详细信息on this page。为了简化使用它,我在这里包含了一个玩具程序,其中包含将UMDH集成到您自己的程序中所需的一切。
玩具程序在不释放内存的情况下分配1000个字符,并包含您需要的UMDH脚手架。这是源代码:
#include <windows.h>
#include <stdio.h>
#include <assert.h>
bool SpawnProcessWin32 (char *command, DWORD &returnCode)
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
bool ret = false;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcessA (NULL, // No module name (use command line).
command, // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
{
DWORD error = GetLastError ();
printf ("error = %d\n", error);
goto exit;
}
// Wait until child process exits.
WaitForSingleObject (pi.hProcess, INFINITE);
// Check exit code
DWORD dwExitCode = 0;
GetExitCodeProcess (pi.hProcess, &dwExitCode);
if(dwExitCode == STILL_ACTIVE)
{
// Process did not terminate -> force it
TerminateProcess (pi.hProcess, 0); // Zero is the exit code in this example
returnCode = 0;
}
else
{
returnCode = dwExitCode;
}
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
ret = true;
exit:
return ret;
}
void foo ()
{
char *buffer = new char [1000];
}
void main (int argc, char *argv[])
{
#if defined (USE_UMDH)
char strCommand [1024];
bool spawnRet;
DWORD retCode;
// For debugging purposes, take initial snapshot of memory
sprintf (strCommand, "C:\\junk\\umdh.exe -p:%ld -f:c:\\junk\\findleak.dump.1", GetCurrentProcessId());
spawnRet = SpawnProcessWin32 (strCommand, retCode);
assert (spawnRet);
#endif
foo (); // This function will leak memory on purpose
#if defined (USE_UMDH)
// For debugging purposes, take terminal snapshot of memory
sprintf (strCommand, "C:\\junk\\umdh.exe -p:%ld -f:c:\\junk\\findleak.dump.2", GetCurrentProcessId());
spawnRet = SpawnProcessWin32 (strCommand, retCode);
assert (spawnRet);
// Now take a diff of the two dumps
sprintf (strCommand, "C:\\junk\\umdh.exe -d c:\\junk\\findleak.dump.1 c:\\junk\\findleak.dump.2 -f:c:\\junk\\findleak.dump.diff", GetCurrentProcessId());
spawnRet = SpawnProcessWin32 (strCommand, retCode);
assert (spawnRet);
#endif
}
以下是需要注意的要点:
当您运行应用程序时,只需检查上次调用umdh.exe生成的diff文件。以下是我对上述玩具计划的看法:
// Debug library initialized ... DBGHELP: DemoUmdh - private symbols & lines c:\junk\TestProjects\DemoUmdh\Debug\DemoUmdh.pdb DBGHELP: ntdll - export symbols DBGHELP: KERNEL32 - export symbols DBGHELP: KERNELBASE - export symbols DBGHELP: MSVCR90D - export symbols // // Each log entry has the following syntax: // // + BYTES_DELTA (NEW_BYTES - OLD_BYTES) NEW_COUNT allocs BackTrace TRACEID // + COUNT_DELTA (NEW_COUNT - OLD_COUNT) BackTrace TRACEID allocations // ... stack trace ... // // where: // // BYTES_DELTA - increase in bytes between before and after log // NEW_BYTES - bytes in after log // OLD_BYTES - bytes in before log // COUNT_DELTA - increase in allocations between before and after log // NEW_COUNT - number of allocations in after log // OLD_COUNT - number of allocations in before log // TRACEID - decimal index of the stack trace in the trace database // (can be used to search for allocation instances in the original // UMDH logs). // + 1036 ( 1036 - 0) 1 allocs BackTrace2 + 1 ( 1 - 0) BackTrace2 allocations ntdll!RtlLogStackBackTrace+7 ntdll!RtlCreateUserThread+15BE5 ntdll!RtlInitializeCriticalSectionEx+129 MSVCR90D!malloc_base+EE MSVCR90D!malloc_dbg+306 MSVCR90D!malloc_dbg+BF MSVCR90D!malloc_dbg+6C MSVCR90D!malloc+1B MSVCR90D!operator new+11 DemoUmdh!foo+28 (c:\junk\testprojects\demoumdh\main.cpp, 64) DemoUmdh!main+A8 (c:\junk\testprojects\demoumdh\main.cpp, 85) DemoUmdh!__tmainCRTStartup+1A8 (f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c, 586) DemoUmdh!mainCRTStartup+F (f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c, 403) KERNEL32!BaseThreadInitThunk+E ntdll!RtlInitializeExceptionChain+85 ntdll!RtlInitializeExceptionChain+58 Total increase == 1036 requested + 28 overhead = 1064
差异报告在应用程序完成后总共增加了大约1036个字节,表明存在泄漏。调用堆栈跟踪显示泄漏的确切位置:
DemoUmdh!foo+28 (c:\junk\testprojects\demoumdh\main.cpp, 64)
这对应于真正的罪魁祸首:
char *buffer = new char [1000];
。
希望这有帮助。
答案 1 :(得分:1)
虽然可以使用CRT进行调试以追踪内存泄漏,但我建议Visual Leak Detector:很好,直接并且集成到Visual Studio 2008,2010和2012中。
如果它只是像这样工作那么我会有完美的拼写!
答案 2 :(得分:0)
对于非常基本和手工制作的内存泄漏搜索,可以使用MS Runtime中的泄漏检测版本。
使用转储,稍后设置断点。这适用于可重现的算法/工作流程。
也许这可能有所帮助。