A delightful CLI tool — and stdio MCP server — for analyzing .NET memory dumps.
Dumpling is a cross-platform .NET global tool that helps developers analyze heap dumps from .NET applications — both .gcdump structure dumps and process dumps (.dmp / core from dotnet-dump). It provides quick command-line analysis, an interactive mode, and an MCP server so AI coding agents can run multi-step leak investigations without reloading dumps or flooding the context window.
- Type Analysis: Group objects by type with counts, sizes, and retained memory
- Retained Size Calculations: Understand true memory impact using dominator tree analysis (
.gcdump) - Leak Suspects: Automatic inspections that rank dominators, heavy holders, large arrays, and root hotspots
- Similar Retention: Group instances of a type by retention-path shape to separate real leaks from noise
- Hot Path to Root: Shortest / most useful retainer path first (scannable leak reading)
- Dominator Tree: Rank objects by exclusive retained size and expand what they exclusively own
- Outgoing References: See what a type/instance holds (complement to retainers)
- Instance Inspection: View sample instances with addresses and individual retained sizes
- Retainer Analysis: Trace reference paths to understand why objects stay in memory
- Process dumps (ClrMD): Full structure analysis (retained size / dominators) and string payloads from
.dmp/ live snapshots - String content: Duplicate detection, top values, search, string-bloat suspects, and string growth in
compare --strings - Multiple Output Formats: Table (default), JSON, or CSV for easy integration
- Interactive Mode: Explore heap data with a rich terminal UI (full structure UI on
.gcdump) - MCP server: Session-based tools for AI agents (
dumpling mcp) — suspects, types, retention clusters, hot paths - Heap Comparison: Compare multiple heap dumps to identify memory growth and changes over time
- Reference Paths: Find GC roots keeping objects alive
- Fast & Efficient: Optimized algorithms for analyzing large heap dumps
| Need | Use |
|---|---|
| Retained size, dominators, retention paths, leak suspects, compare growth | .gcdump or process dump (ClrMD builds a structure graph) |
| String values, duplicate strings, content search, string-bloat suspects | Process dump / live snapshot (collect --kind heap or analyze --pid) |
| Fastest structure-only capture | .gcdump (smaller file, EventPipe) |
dotnet tool install -g dotnet-dumplingAnalyze a heap dump and display the top 20 types by retained size:
dumpling analyze heap.gcdumpShow more or fewer types:
dumpling analyze heap.gcdump --top-types 50Filter types by name (regex):
dumpling analyze heap.gcdump --filter "String|Byte\[\]"When you open a dump with no hypothesis, run automatic inspections:
dumpling analyze heap.gcdump --suspects
dumpling analyze heap.gcdump --suspects --format json > suspects.jsonHeuristics surface:
- Dominators — single instances retaining a large share of the heap
- Heavy holders — types whose retained size greatly exceeds shallow size
- Array hogs — large
T[]populations - Root hotspots — statics / handles / finalizer patterns in high-retained samples
Group instances by the shape of their path to a GC root (addresses ignored):
dumpling analyze heap.gcdump --filter "MyApp.CacheEntry" --group-by-retention
dumpling analyze heap.gcdump -t 5 --group-by-retention --retention-types 3This is the CLI equivalent of dotMemory’s “Similar Retention”: e.g. 12k byte[] held by a cache vs 3 held by HttpClient appear as separate clusters.
With --show-retainers, Dumpling shows the hot path (shortest BFS path to root) by default. Use --max-paths N for additional alternate paths.
dumpling analyze heap.gcdump --show-retainers
dumpling analyze heap.gcdump --show-retainers --max-paths 3Rank instances by exclusive retained size and expand the largest object's dominated children:
dumpling analyze heap.gcdump --dominators
dumpling analyze heap.gcdump --dominators --format jsonInteractive mode includes a Dominator Tree browser (expand / back up / show outgoing).
See what objects hold (opposite of retainers):
dumpling analyze heap.gcdump --show-outgoing
dumpling analyze heap.gcdump -t 5 --show-outgoing --show-retainersExport results as JSON for further processing:
dumpling analyze heap.gcdump --format json > analysis.jsonExport as CSV for Excel analysis:
dumpling analyze heap.gcdump --format csv > analysis.csvLaunch the interactive terminal UI to explore the heap:
dumpling analyze heap.gcdump --interactiveIn interactive mode, you can:
- Run Leak Suspects automatic inspections
- Browse the Dominator Tree (expand exclusive children)
- Navigate through types and instances
- Group by retention for a selected type
- View outgoing references (type-wide or largest instance)
- Expand dominator children of the largest instance of a type
- Search and filter objects
- Drill down into retainers / hot paths
- Export selected data
Compare interactive mode mirrors growth analysis:
- Growth Suspects (same as
--suspects) - Why Did Types Grow? (same as
--why-grew) - Per-type: why this type grew, retention clusters, outgoing on current dump
Compare multiple heap dumps to identify memory growth and changes:
dumpling compare before.gcdump after.gcdumpShow only types with significant growth:
dumpling compare before.gcdump after.gcdump --threshold 0.05 # 5% minimum changeInteractive comparison exploration:
dumpling compare before.gcdump after.gcdump --interactiveGrowth-focused suspects (added / grown types):
dumpling compare before.gcdump after.gcdump --suspectsExplain why the biggest growers stay alive (similar retention on the current dump):
dumpling compare before.gcdump after.gcdump --why-grew
dumpling compare before.gcdump after.gcdump --suspects --why-grew --why-grew-types 8Run Dumpling as a Model Context Protocol stdio server so agents can open a dump once and drill down with small, structured tool results:
dumpling mcpExample host config (Cursor / VS Code / Claude Desktop style):
{
"mcpServers": {
"dumpling": {
"command": "dumpling",
"args": ["mcp"]
}
}
}Or from a local clone without installing the tool:
{
"mcpServers": {
"dumpling": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/dotnet-dumpling/src/Dumpling.CLI", "--", "mcp"]
}
}
}Session: heap_open, heap_list_sessions, heap_describe, heap_close, heap_detect
Investigate: heap_suspects, heap_types, heap_instances, heap_retention_clusters, heap_hot_path, heap_retainers, heap_dominators, heap_dominator_children, heap_outgoing
Compare: heap_compare_open, heap_compare_deltas, heap_compare_suspects, heap_why_grew, heap_compare_strings
Strings (process dump): heap_top_strings, heap_duplicate_strings, heap_search_strings, heap_string_at
Live: dotnet_ps, heap_collect (needs confirm=true), heap_open_live
Prompts: investigate-leak, compare-growth, string-bloat, live-triage
Resources: dumpling://sessions, dumpling://session/{sessionId}
Design notes:
- Dumps stay loaded in-process (
sessionId); tools return minified JSON with small defaults (top10, hard caps). - Responses include a short
summaryand optionalsuggestedNexttool calls instead of bulk tables. - Prefer the named prompts over inventing a dump workflow.
- String tools redact previews by default (secrets/tokens). Process dumps are sensitive.
- File capture (
heap_collect,heap_open_livewith gcdump/heap/full) requiresconfirm=true. SetDUMPLING_MCP_ALLOW_COLLECT=0to disable.
Run the stdio MCP server (logs go to stderr only).
List .NET processes that published a diagnostics channel (attachable).
Collect a dump from a running process.
dumpling collect -p <pid> --kind heap|gcdump|full [-o path]
dumpling collect -n MyApp --kind gcdumpMain analysis command for heap dumps (.gcdump or process dump) or a live process.
Options:
--pid, -p <pid>/--process, -n <name>: Analyze a live process (optional file path)--kind, -k <kind>: Live mode:snapshot(default for strings),gcdump,heap,full--top-types, -t <number>: Number of top types to display (default: 20)--format, -f <format>: Output format: Table, Json, or Csv (default: Table)--filter, -F <regex>: Case-insensitive type name filter (regex)--interactive, -i: Launch interactive mode (full structure UI for.gcdump; string-focused UI for process dumps with top/duplicates/search, type samples + value previews, export, live refresh)--show-instances, -si: Show sample instances for each type--show-retainers, -sr: Show retainer paths for instances (implies --show-instances)--max-instances, -mi <number>: Maximum instances to show per type (default: 3)--sample-nodes, -sn <number>: Sample large dumps down to ~N nodes for faster analysis--min-retained <bytes>: Only include types with retained size ≥ N bytes (e.g.1048576= 1 MiB)--min-count <n>: Only include types with instance count ≥ N--suspects, -S: Run automatic leak-suspect heuristics--group-by-retention, -gr: Cluster instances of top types by retention-path shape--retention-types <n>: How many top types to cluster with--group-by-retention(default: 3)--max-paths <n>: Max reference paths per instance when showing retainers (default: 1 = hot path)--dominators, -D: Show top dominators and expand children of the largest--show-outgoing, -so: Show outgoing references for top types / sample instances--top-strings <n>: Top unique string values by total size (process dump)--duplicates: Group duplicateSystem.Stringinstances by content (process dump)--search-strings, -q <text>: Search string object content (process dump)--search-regex: Treat--search-stringsas a regex--min-string-count <n>: Min instances per string group (duplicates floor at 2)--min-string-bytes <n>: Min total shallow size per string group--string-preview <n>: Max preview characters (default 80;0hides content)--max-strings-scan <n>: Cap how many string instances to scan (default 500000;0unlimited)
Process dump examples:
dotnet-dump collect -p <pid> --type heap -o app.dmp
dumpling analyze app.dmp --top-types 20
dumpling analyze app.dmp --duplicates --top-strings 30
dumpling analyze app.dmp --search-strings "connectionstring" --format jsonPrivacy: process dumps contain live string content (secrets, tokens, PII). Prefer
--string-preview 0in shared logs; treat dump files as sensitive.
Compare multiple heap dump files to identify changes and memory growth.
Options:
--interactive, -i: Launch interactive mode for exploring comparison results--select-files, -sf: Launch interactive file selection when multiple files are found--format, -f <format>: Output format: Table, Json, or Csv (default: Table)--filter, -F <regex>: Case-insensitive type name filter (regex)--top-types, -t <number>: Number of top changed types to display (default: 20)--threshold, -th <threshold>: Minimum change percentage to display (default: 0.01 = 1%)--show-all, -a: Show all types including unchanged ones--sort-by, -s <field>: Sort byRetainedSizeDelta(growth first, default),CountDelta,TotalSizeDelta, orGrowthPercent--min-retained <bytes>: Keep types with current retained size ≥ N (Added/Removed always included)--min-count <n>: Keep types with current count ≥ N (Added/Removed always included)--suspects, -S: Highlight growth-based leak suspects (added / grown types)--why-grew, -w: For top grown/added types, cluster instances on the current dump by retention path--why-grew-types <n>: How many grown types to explain (default: 5)--strings: Compare string content profiles between two process dumps (growing/shrinking unique string groups)
dumpling ps # list attachable .NET processes
dumpling collect -p <pid> --kind heap # process dump → string analysis
dumpling collect -p <pid> --kind gcdump # structure dump → retained size / suspects
dumpling analyze --pid <pid> --duplicates --top-strings 20 # live ClrMD snapshot
dumpling analyze --pid <pid> --kind gcdump --suspects # live → temp .gcdump → analyze--kind for collect: heap (default), gcdump, full.
--kind for live analyze: snapshot (default for strings), gcdump, heap, full.
dotnet tool install -g dotnet-gcdump # optional; dumpling collect --kind gcdump also works
dotnet-gcdump collect -p <process-id>
dumpling analyze heap.gcdump --suspectsAlso: Visual Studio Diagnostic Tools → snapshot → export .gcdump, or PerfView → Heap Snapshot.
dumpling collect -p <process-id> --kind heap -o app.dmp
# or: dotnet-dump collect -p <process-id> --type heap -o app.dmp
dumpling analyze app.dmp --duplicates --top-strings 25Heap dumps are usually enough for managed string analysis; use --kind full only when you need broader native state.
Platform notes: live attach needs permission to inspect the target (same user, or
CAP_SYS_PTRACE/ debugger rights). On Linux/macOS a ClrMD live snapshot may write a temporary coredump.
┌─────────────────────────┬────────┬──────────────┬────────────────┬──────────┐
│ Type │ Count │ Total Size │ Retained Size │ % of Heap│
├─────────────────────────┼────────┼──────────────┼────────────────┼──────────┤
│ System.String │ 10,234 │ 2.45 MB │ 15.67 MB │ 23.45% │
│ System.Byte[] │ 1,523 │ 5.12 MB │ 12.34 MB │ 18.47% │
│ MyApp.CustomerData │ 856 │ 1.23 MB │ 8.91 MB │ 13.34% │
└─────────────────────────┴────────┴──────────────┴────────────────┴──────────┘
- Type: The .NET type name
- Count: Number of instances
- Total Size: Direct memory used by all instances
- Retained Size: Sum of per-instance retained sizes (see note below)
- % of Heap: Percentage of total retained heap size (using that sum)
Retained size (per object): The amount of memory that would be freed if that object and everything it exclusively dominates were garbage collected. Calculated via a dominator / spanning-tree pass. Often more useful than the object's own size when hunting leaks.
Type-level retained size (Dumpling’s table column): The sum of each instance’s retained size for that type. Shared subgraphs can be counted more than once when several instances of the same type dominate overlapping descendants, so the column can exceed exclusive impact or even the total heap. Treat it as a ranking signal (“these types look heavy”), then drill into instance retained sizes and retainer paths for truth. JSON field Types[].RetainedSize uses the same definition; SchemaVersion is currently 3 (process-dump payloads may include TopStrings / DuplicateStrings / StringMatches).
Hot path: The shortest retainer path from a GC root to an instance (BFS). Usually enough to identify why something is alive without dumping every alternate path.
Similar retention: Instances of one type clustered by path signature (RootKind + type chain). Different clusters usually mean different product bugs or different intended caches.
Dominator tree: Object X dominates Y if every path from a GC root to Y goes through X. A node's retained size is (roughly) the memory that disappears if that node is collected. Expanding dominator children answers “what does this exclusively own?”
Outgoing references: Direct edges in the object graph from a node to its children — “what does this hold?” — independent of exclusive ownership.
Root kinds: Retainer paths classify how the object is rooted (static fields, locals/stack, handles, COM/WinRT, …) from the dump’s special graph nodes.
Sampling large dumps: --sample-nodes N reduces the heap graph with EventPipe’s GraphSampler when the dump exceeds N nodes, then scales type counts back toward full-heap estimates.
Dominator tree: An object X dominates object Y if every path from the root to Y goes through X.
Recommended workflow:
# 1. Automatic shortlist
dumpling analyze app.gcdump --suspects
# 2. See what exclusively owns the heap
dumpling analyze app.gcdump --dominators
# 3. Focus a suspicious type: retention shape + what it holds
dumpling analyze app.gcdump --filter "MyApp.LeakyType" --group-by-retention --show-outgoing --show-retainers
# 4. Confirm growth and see retention shapes for growers
dumpling compare before.gcdump after.gcdump --suspects --why-grewOr start from the type table when you already have a hypothesis:
dumpling analyze app.gcdump --top-types 50Types with high retained size relative to their expected usage often indicate memory leaks.
See why objects are staying in memory:
# Show instances and their retainer paths
dumpling analyze app.gcdump --show-retainers
# Get detailed JSON output for analysis
dumpling analyze app.gcdump --show-retainers --format json > retention.jsonFor large production dumps, export to JSON for detailed analysis:
dumpling analyze prod.gcdump --format json | jq '.Types[] | select(.RetainedSize > 10000000)'Compare multiple heap dumps to track memory changes over time:
# Basic comparison showing memory growth
dumpling compare before.gcdump after.gcdump
# Focus on significant changes only
dumpling compare dump1.gcdump dump2.gcdump dump3.gcdump --threshold 0.1
# Export comparison results for analysis
dumpling compare before.gcdump after.gcdump --format json > comparison.json
# Interactive exploration of changes
dumpling compare before.gcdump after.gcdump --interactiveFocus on problematic types with instance details:
# Show 5 instances of each top type
dumpling analyze app.gcdump --top-types 10 --show-instances --max-instances 5- .NET 10.0 or later
- Windows, macOS, or Linux
Apache License 2.0 - see LICENSE file for details.
Dumpling's heap analysis algorithms are inspired by the excellent work in:
- PerfView
- dotnet-heapview
- Microsoft.Diagnostics.Tracing.TraceEvent
Because we're analyzing dump files, and dumplings are delightful! 🥟