How to Find a Windows Memory Leak
Rank outstanding allocations by stack, diff two moments, resolve the call site.
A process's committed bytes can rise for many reasons: a heap that never releases, a cache with no eviction, mapped views left open, or a slow drip of VirtualAlloc calls that are never freed. Memory Explorer turns that single rising number into something you can act on — outstanding allocations grouped by the call stack that made them, ranked so the leak floats to the top.
The Sixty-Second Workflow
- Run Memory Explorer elevated and press Start (Ctrl+E).
- Pick the target in the Process combo to attach and seed the address map.
- Let the workload run so a leak has time to accumulate.
- Read the top row of Outstanding allocations — it auto-selects the fastest-growing group.
- Select that group to resolve its allocating call stack.
- Confirm by re-running the scenario or scrubbing the timeline.
Because the ranking sorts by trailing growth first and outstanding bytes second, a genuine leak climbs to the top on its own — you rarely have to read past the first row or two.
Start the Capture and Attach
Starting a capture opens the kernel session with VirtualAlloc/VirtualFree stack tracing. When you pick a process, Memory Explorer seeds its address map with a VirtualQueryEx snapshot taken after the session starts, so nothing is missed, and then applies live deltas as allocations and frees arrive. Configure your PDB search path first (Options → Configure Paths) so the allocation stack resolves to real function names when you need it.
Read the Outstanding-Allocation Ranking
The outstanding-allocations grid is the main evidence view. Each row is a group of live VirtualAlloc regions that share an allocating stack. The most useful columns are:
- Count: live allocations in the group.
- Outstanding: bytes currently committed by the group.
- Growth: change over the trailing window — the primary sort key.
- Median age: how long the group's regions have been alive, which helps separate a steady leak from short-lived churn.
Seeded allocations that pre-date your attach never count as growth, so the baseline can never outrank a real leak. Press Ctrl+C in the grid to copy the whole table as tab-separated text for a bug report.
Use the A/B Diff
When you want to attribute growth to a specific operation, press Mark A to anchor the current playhead, then run the suspect path. Regions born after A — present now but absent at A — are outlined on the address map, the timeline shades the A-to-playhead range, and the header reports since A: +N regions (bytes) / -M regions (bytes). It is the two-snapshot memory hunt, but with the map and the stacks already attached. Press Clear A to leave diff mode.
Scrub the Timeline
The timeline plots committed bytes over time with per-event ticks. Drag the playhead (or use Left / Right / Home / End) to move the whole view to "state as of T" — the address map and the allocation grid both rewind to that instant, so you can watch a region appear and never disappear. "Jump to now" returns to live. A true leak shows committed bytes that rise and stay up; a region whose bytes rise during an operation and then fall back is usually delayed release, not a leak.
Resolve the Allocating Stack
Select the leading group and Memory Explorer symbolizes its allocating stack on demand from your configured PDB search path. Lazy symbolization keeps the live capture fast because the event stream is not symbolized row by row. Kernel frames resolve from the Microsoft symbol path; your application frames need the PDBs for the exact build you are testing.
Drill Into the Raw Events
Every alloc, free, map, and unmap is also a row in the Events list, where filtering, search, highlight rules, and export all apply. The grp=token on a row matches that row's allocation-stack group, so you can pivot from a suspicious group straight to the individual events behind it.
When It Is Not VirtualAlloc
Not every leak is process VirtualAlloc. If a driver is leaking kernel pool, switch to the System view, where pool tags are ranked by outstanding bytes with growth sparklines — the poolmon workflow, with history. For resident-memory questions about a specific region, select it and use the working-set panel, which reports resident versus nonresident-or-unknown committed pages rather than guessing a standby/modified/compressed breakdown Windows does not publish.
Frequently Asked Questions
Does Memory Explorer show which code path leaked the memory?
Yes. Outstanding VirtualAlloc regions are grouped by allocating stack. Selecting the leading group resolves its representative call stack from your PDB search path, so the leak is tied to a process, region kind, and call site rather than only a committed-bytes total.
Will allocations that existed before I attached look like a leak?
No. When you attach, pre-existing allocations are seeded from a VirtualQueryEx snapshot taken after the session starts, and seeded allocations never count as growth. A fresh attach therefore cannot rank the baseline above a real leak; only allocations that grow after attach climb the ranking.
Can I compare two points in time?
Yes. Press Mark A to anchor the current playhead, then let the suspect operation run. Regions present at the playhead but absent at A are outlined on the map, the timeline shades the A-to-now range, and the header reports the region and byte counts gained and lost since A.
What if the leak is not VirtualAlloc — is it pool or working set?
The System view tracks kernel pool tags ranked by outstanding bytes with growth trends, which is the right place for a nonpaged or paged pool leak. For resident-memory questions on a selected region, the working-set panel reports resident versus nonresident/unknown committed pages.
For related diagnostics, see how to track down handle leaks, Windows kernel debugging services, and the Memory Explorer views guide.
Memory Explorer
What our customers say about us?

Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials
