Skip to content

Change heap dumps to use HEAP2 as the default#127321

Merged
hoyosjs merged 6 commits into
dotnet:mainfrom
hoyosjs:juhoyosa/heap2-default
Apr 24, 2026
Merged

Change heap dumps to use HEAP2 as the default#127321
hoyosjs merged 6 commits into
dotnet:mainfrom
hoyosjs:juhoyosa/heap2-default

Conversation

@hoyosjs
Copy link
Copy Markdown
Member

@hoyosjs hoyosjs commented Apr 23, 2026

This pull request simplifies and unifies the logic for memory region enumeration when generating heap dumps. It makes HEAP2 the default heap dump and deprecates old env vars that work around slow dumps. It assumes LocaderAllocators have all necessary data. This path does a few things better and is higher perf. It enumerates the following:

Enumerates
JitManager -> Code Heaps
SystemDomain -> GlobalLoaderAllocator (was missing before partially).
AppDomain -> LoaderAllocator
Assembly -> LoaderAllocator
Module -> LoaderAllocator
LoaderAllocator -> All Loader Heaps (also collecting collectible ones now).

It skips

  • Objects living in the loader alloc: Module hashtables, ClassLoader explicit enumeration, EEClass MethodDescChunks, MethodTable DispatchMap.
  • Thread AppDomain, Debugger Module info, Debugger MethodDesc info which have already been enumerated.

Copilot AI review requested due to automatic review settings April 23, 2026 13:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes CoreCLR heap-dump memory region enumeration to use the HEAP2 path by default, removing legacy/slow enumeration paths and createdump environment-variable workarounds.

Changes:

  • Removes several legacy EnumMemoryRegions sub-enumerations that were skipped for HEAP2 and primarily supported the older heap-dump path.
  • Forces heap dump generation through CLRDATA_ENUM_MEM_HEAP2 in DAC enumeration and createdump’s DAC-based region enumeration.
  • Simplifies the “custom dump” enumeration worker to a single mini-style path.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/coreclr/vm/threads.cpp Removes AppDomain enumeration from thread region enumeration for non-HEAP2 legacy paths.
src/coreclr/vm/methodtable.cpp Drops DispatchMap explicit enumeration for legacy non-HEAP2 dump paths.
src/coreclr/vm/class.cpp Removes explicit Module + MethodDescChunk enumeration for legacy non-HEAP2 dump paths.
src/coreclr/vm/ceeload.cpp Removes extensive Module hashtable/type/member explicit enumeration for legacy non-HEAP2 dump paths; keeps HEAP2 loader allocator enumeration.
src/coreclr/vm/assembly.cpp Removes legacy Assembly sub-enumerations; keeps HEAP2 loader allocator enumeration only.
src/coreclr/debug/ee/functioninfo.cpp Removes legacy debugger module/methoddesc/sequence-map explicit enumeration for non-HEAP2 paths.
src/coreclr/debug/daccess/enummem.cpp Makes heap dumps always run via HEAP2; simplifies Custom dump worker and removes HEAP handling in wrapper.
src/coreclr/debug/createdump/crashinfo.cpp Removes env-var-based opt-out/compat behavior; always uses HEAP2 for DAC-based enumeration.

Comment thread src/coreclr/debug/daccess/enummem.cpp
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

Comment thread src/coreclr/debug/createdump/crashinfo.cpp Outdated
Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 23, 2026 17:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/debug/daccess/enummem.cpp
Comment thread src/coreclr/debug/createdump/crashinfo.cpp
Comment thread src/coreclr/debug/createdump/crashinfo.cpp Outdated
Comment thread src/coreclr/debug/createdump/crashinfo.cpp Outdated
Comment thread src/coreclr/debug/createdump/crashinfo.cpp Outdated
Comment thread src/coreclr/debug/createdump/crashinfo.cpp Outdated
Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 23, 2026 21:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/coreclr/debug/daccess/enummem.cpp:1951

  • EnumMemoryRegionsWrapper() no longer handles CLRDATA_ENUM_MEM_HEAP even though it remains a public flag in clrdata.h. Passing CLRDATA_ENUM_MEM_HEAP will now hit the debug assert and (in retail) effectively do nothing while still returning S_OK. Consider mapping HEAP -> HEAP2 for backward compatibility, or returning a failing HRESULT (e.g., E_INVALIDARG) to avoid silent success.
        else if (flags == CLRDATA_ENUM_MEM_TRIAGE)
        {
            // triage micro-dump
            status = EnumMemoryRegionsWorkerMicroTriage(flags);
        }
        else if (flags == CLRDATA_ENUM_MEM_HEAP2)
        {
            status = EnumMemoryRegionsWorkerHeap(flags);
        }
        else
        {
            _ASSERTE(!"Bad flags passing to EnumMemoryRegionsWrapper!");
        }
    }

Comment thread src/coreclr/debug/daccess/enummem.cpp
@hoyosjs hoyosjs enabled auto-merge (squash) April 23, 2026 22:56
@hoyosjs hoyosjs merged commit c835d0f into dotnet:main Apr 24, 2026
109 checks passed
@hoyosjs hoyosjs deleted the juhoyosa/heap2-default branch April 24, 2026 08:09
@rcj1 rcj1 mentioned this pull request Apr 28, 2026
hoyosjs added a commit that referenced this pull request May 13, 2026
Fixes #122459

main PRs:
- #125631
- #125459
- #127321

# Description

Backports three DAC performance improvements for minidump collection:

1. **Use SHash as DAC instance hash (#125631):** Replaces the
hand-rolled hash table in `DacInstanceManager` with an `SHash`-based
implementation. The previous fixed-bucket hash degraded quickly for Find
and insertion operations under high load. Measured ~9.5x speedup for
minidump collection against a repro app with 2.5k-frame deep stacks over
50 threads.

2. **Cache debugger patches (#125459):** Caches the list of debugger
breakpoint patches so that x64 stack unwinding doesn't re-scan the
1,000-bucket patch hash table on every frame. The cache is populated
once on first access and invalidated on `Flush()`. Measured reduction
from 55s to ~7s for minidump collection (10,000 iterations across 10
threads).

3. **Enable CLRDATA_ENUM_MEM_HEAP2 via environment variable:** When the
target process has `DOTNET_EnableFastHeapDumps` set, the DAC promotes
`CLRDATA_ENUM_MEM_HEAP` to `CLRDATA_ENUM_MEM_HEAP2`, which dumps loader
heap pages in bulk instead of walking individual runtime structures.

# Customer Impact

Customers collecting minidumps of large .NET applications (many threads,
deep stacks) experience extremely slow dump collection times - on the
order of minutes for what should take seconds. This directly impacts
incident response time in production environments. Without these fixes,
dump collection through Watson/dotnet-dump/createdump remains
unacceptably slow for large workloads.

# Regression

Yes, with respect to framework. Customers doing migrations have noticed
them - framework used non-portable variants of the MSVC library.

# Testing

- Both PRs (#125631, #125459) were merged to main and have been stable.
- Performance was measured against a repro app exercising deep stacks
across many threads, confirming the expected speedups.
- The env var change is gated behind an explicit opt-in
(`DOTNET_EnableFastHeapDumps`), so no change in default behavior. This
is the riskier change since it makes heap dump match our expectations
but might yield unknown!unknown if the modules aren't indexed properly.

# Risk

**Low.** 

- The SHash and patch cache changes are confined to DAC-only code paths
(`daccess.cpp`, `dacfn.cpp`, `dacimpl.h`) that execute only during
diagnostic operations (dump collection, debugging). They do not affect
runtime execution.
- The `DOTNET_EnableFastHeapDumps` env var is opt-in and does not change
default behavior.
- All three changes have been running in main since March without
reported issues.
hoyosjs added a commit that referenced this pull request May 13, 2026
Fixes #122459

main PRs:
- #125631
- #125459
- #127321

# Description

Backports three DAC performance improvements for minidump collection:

1. **Use SHash as DAC instance hash (#125631):** Replaces the
hand-rolled hash table in `DacInstanceManager` with an `SHash`-based
implementation. The previous fixed-bucket hash degraded quickly for Find
and insertion operations under high load. Measured ~9.5x speedup for
minidump collection against a repro app with 2.5k-frame deep stacks over
50 threads.

2. **Cache debugger patches (#125459):** Caches the list of debugger
breakpoint patches so that x64 stack unwinding doesn't re-scan the
1,000-bucket patch hash table on every frame. The cache is populated
once on first access and invalidated on `Flush()`. Measured reduction
from 55s to ~7s for minidump collection (10,000 iterations across 10
threads).

3. **Enable CLRDATA_ENUM_MEM_HEAP2 via environment variable:** When the
target process has `DOTNET_EnableFastHeapDumps` set, the DAC promotes
`CLRDATA_ENUM_MEM_HEAP` to `CLRDATA_ENUM_MEM_HEAP2`, which dumps loader
heap pages in bulk instead of walking individual runtime structures.

# Customer Impact

Customers collecting minidumps of large .NET applications (many threads,
deep stacks) experience extremely slow dump collection times - on the
order of minutes for what should take seconds. This directly impacts
incident response time in production environments. Without these fixes,
dump collection through Watson/dotnet-dump/createdump remains
unacceptably slow for large workloads.

# Regression

Yes, with respect to framework. Customers doing migrations have noticed
them - framework used non-portable variants of the MSVC library.

# Testing

- Both PRs (#125631, #125459) were merged to main and have been stable.
- Performance was measured against a repro app exercising deep stacks
across many threads, confirming the expected speedups.
- The env var change is gated behind an explicit opt-in
(`DOTNET_EnableFastHeapDumps`), so no change in default behavior. This
is the riskier change since it makes heap dump match our expectations
but might yield unknown!unknown if the modules aren't indexed properly.

# Risk

**Low.** 

- The SHash and patch cache changes are confined to DAC-only code paths
(`daccess.cpp`, `dacfn.cpp`, `dacimpl.h`) that execute only during
diagnostic operations (dump collection, debugging). They do not affect
runtime execution.
- The `DOTNET_EnableFastHeapDumps` env var is opt-in and does not change
default behavior.
- All three changes have been running in main since March without
reported issues.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants