Reputation: 1173
I've been adapting this code (the c++ version) to my needs, which involves running over a very long video sequence. After a few hundred frames, the program crashes due to memory issues. If i check the memory used by the process, it is using more than 1.6 GB RAM. Checking memory usage (in a very dumb way using windows task manager..) i've noticed that every frame uses pretty much the same amount of extra memory.
I've been told that using MS Visual Studio (the IDE i'm currently using) i should be able to see, at a certain point, which variables are using more memory, in order to find which one is causing the memory leak and to fix it, but i couldn't find anything about it in the IDE.
If possibile, i'd like not to use tools like Valgrind and solve the problem using Visual Studio. If not..well, i'll think about that when i'll get there :)
Thanks!
Upvotes: 0
Views: 2329
Reputation: 2892
Whilst it is possible to use CRT to debug to track down memory leaks, I would recommend Visual Leak Detector: nice, straight-forward and integrates into Visual Studio 2008, 2010 and 2012.
PS: apologies for how long this post went un-spell-checked: I blame the manufacturers of my finingerses firmware for not releasing an update in time! ;-)
If only it worked like this then I would have perfect spelling!
Upvotes: 1
Reputation: 4366
For very basical and hand made memory leak search the leak detection build in the MS Runtime can be used.
A dump is used and breakpoints are set later on. This works well for algorithms/workflows that are reproducible.
Maybe this could help.
Upvotes: 0
Reputation: 1982
I have found that Microsoft's UMDH ("user-mode dump heap") tool has saved me time and again. You can find detailed information on this page. To simplify using it, I'm including here a toy program that has everything you'll need to integrate UMDH into your own program.
The toy program allocates 1000 chars without releasing the memory, and includes the UMDH scaffolding you need. Here's the source code:
#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
}
Here are the points to take note of:
When you've run your app, just check the diff file produced by the last call to umdh.exe. Here's what I get with the above toy program:
// 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
The diff reports a total increase of some 1036 bytes after the app finished, indicating a leak. The calling stack trace shows the exact location of the leak:
DemoUmdh!foo+28 (c:\junk\testprojects\demoumdh\main.cpp, 64)
This corresponds to the true culprit:
char *buffer = new char [1000];
.
Hope this helps.
Upvotes: 2