The Current Landscape of Native Memory Diagnostics
Leak diagnostics is a nasty business in native applications. There have been many attempts at solving this problem automatically. To name a few:
- The CRT Debug Heap (
which is no longer used by default in Visual Studio 2015!– See update below.) can help identify memory leaks by associating each allocation with additional data on the allocating source file and line number. At program exit (or whenever a special CRT function is called), all blocks that haven’t been freed are printed out. This has been around forever. The problem is that you need to compile with the CRT debug heap enabled, so you can’t pick an arbitrary application and start analyzing it for memory leaks. It’s still a useful technique, and one used by Boost Test. If you’re interested, here’s a great walkthrough.
UPDATE: Where would I be without you, dear readers! Ofek Shilon points out that it’s the Windows debug heap that’s being phased out by default in Visual Studio 2015, and not the CRT Debug Heap, which is still alive and kicking. Here’s his post on the subject.
- UMDH (from the Debugging Tools for Windows) can diagnose memory leaks by using built-in Windows support for capturing allocation stack traces. When properly configured, the Windows heap manager will keep track of all outstanding allocations and their stack traces, and umdh.exe can compare allocation snapshots as the program is executing and determine which blocks haven’t been freed. Unlike the CRT debug heap, you get a call stack for each leaking allocation, and you get aggregation so if you leaked 1,000 blocks from a single source location, you only see it once in the report. Moreover, unlike the CRT debug heap, you don’t need any ahead-of-time preparation. You can use UMDH to diagnose any application without recompiling.
- The Windows heap manager is instrumented with ETW events (HeapAlloc/HeapRealloc/HeapFree), and WPA can aggregate them to show you blocks that were allocated but not freed during a particular trace you record. If you enable stack walking, you can get allocation call stacks as well. Again, just like UMDH, this doesn’t require ahead-of-time preparation and works with optimizations enabled.
I think the key problem with all the approaches above is the amount of configuration they require. Most C++ developers want leak analysis to be available in their IDE, and get the information at their fingertips without running an additional tool and subjecting themselves to complex trace analysis. (UMDH reports are known for being user-unfriendly, and WPA has its quirks as well.)
Native Memory Leak Diagnostics in Visual Studio 2015
Visual Studio 2015 makes native leak analysis a lot easier for most developers. You will still need UMDH or ETW for production debugging and leak detection, but in the comfort of your development workstation, Visual Studio should be able to suit your needs. Basically, you recompile with the Visual C++ 2015 compiler, and then run your app with or without the debugger with the new Diagnostic Tools mode enabled (you can get there using the Alt+F2 keyboard shortcut). To get this working while debugging, you will need to configure a special registry key. This requirement will hopefully go away at RTM, but for now you can find the instructions here.
While the tools are running, you get a nice graph of memory utilization and can capture heap snapshots. You can see right away how many bytes you’re leaking and how many individual allocations they are coming from. In this case, over a span of just a few seconds we leaked over 2.5MB of memory.
If you pick a specific snapshot, you can see details on what types are in that snapshot and how much memory is taken by objects of each type.
Heap snapshots can be compared, producing easy to read information on which types of allocations are likely leaking. Looks like we have arrays of CPU_INFO_INTERNAL and objects of BATTERY_INFO_INTERNAL taking up lots of memory. All other types line up with no count delta.
And finally, you can dive in and see a list of all objects of a particular type, including their contents and where each individual object was allocated. This is probably the killer feature — you can look at the actual object contents if you like. That’s not something you get out of ETW or UMDH. You can also double click frames on the allocation call stack to jump to the source code.
It’s worth reiterating that this works with optimizations enabled. The screenshots above were produced using an optimized version. It does have an effect on call stack accuracy if frames are being inlined. In the preceding screenshot, the call stack appears as though TemperatureAndBatteryUpdaterThread called operator new directly. In fact, it called a constructor for a type called BatteryInformation, which isn’t visible in the call stack because it was inlined. (You might expect the /Zo switch to make a difference, but presently it doesn’t. I’ll be sure to check future versions for better inline debugging support.)
Visual Studio 2015 has really nice native memory debugging support. You can capture heap snapshots, compare them, and get to the bottom of memory leaks by looking at diffs and inspecting individual objects and their allocating call stacks. This experience is much more friendly than anything previously available (CRT debug heap, UMDH, ETW) and will make leak analysis more streamlined for all native developers.
I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn