Skip to content

Fix NullReferenceException in SegmentedList.Add during large heap snapshots#2391

Closed
Copilot wants to merge 1 commit intomainfrom
copilot/fix-nullreferenceexception-heap-snapshot
Closed

Fix NullReferenceException in SegmentedList.Add during large heap snapshots#2391
Copilot wants to merge 1 commit intomainfrom
copilot/fix-nullreferenceexception-heap-snapshot

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 20, 2026

Taking a heap snapshot on large heaps (100M+ objects) throws System.NullReferenceException inside SegmentedList<T>.Add via Graph.SetNodeTypeAndSizeNode.WriteCompressedInt.

Root Cause

SegmentedMemoryStreamWriter.Clear() was replacing the backing bytes list with a brand-new empty SegmentedList<byte>:

// Before
public virtual void Clear() { bytes = new SegmentedList<byte>(131_072); }

Graph.ClearWorker() creates the writer with a large initial capacity (m_expectedNodeCount * 8, up to ~1 GB for 128M-node graphs) and then immediately calls m_writer.Clear(), discarding that entire pre-allocation. The replacement list starts with items = null. When Write(byte) is JIT-inlined into WriteCompressedInt, calling bytes.Add(value) on this fresh null-items list under memory pressure results in a NullReferenceException inside SegmentedList.Add. There's also a segment-size inconsistency: the constructor uses segmentSize = 65_536; Clear() was creating a new list with segmentSize = 131_072.

Fix

Reset the count of the existing bytes list rather than replacing it:

// After
public virtual void Clear() { bytes.Count = 0; }

This preserves the pre-allocated buffer (eliminating the wasted ~1 GB allocation and the items = null state), keeps the segment size consistent, and removes the NullReferenceException risk.

Changes

  • src/FastSerialization/SegmentedMemoryStreamWriter.cs — one-line fix to Clear()
  • src/FastSerialization.Tests/SegmentedMemoryStreamWriterTests.cs — new tests covering Clear() semantics, write/read round-trips, multiple clear cycles, and cross-segment-boundary writes
Original prompt

This section details on the original issue you should resolve

<issue_title>System.NullReferenceException while taking heap snapshot</issue_title>
<issue_description>Version: P2.0.42 (64 bit)
Max Dump K objects: 250
Freeze: No
Save ETL: No

Tail of log:

1070.1s: Dumped 114,354,847 objects, max_dump_limit 134,217,716 Dumper heap Size 7,384MB
HeapDump Error: System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Collections.Generic.SegmentedList`1.Add(T item)
   at Graphs.Node.WriteCompressedInt(SegmentedMemoryStreamWriter writer, Int32 value)
   at Graphs.Graph.SetNodeTypeAndSize(NodeIndex nodeIndex, NodeTypeIndex typeIndex, Int32 sizeInBytes)
   at Graphs.Graph.SetNode(NodeIndex nodeIndex, NodeTypeIndex typeIndex, Int32 sizeInBytes, GrowableArray`1 children)
   at GCHeapDumper.DumpAllSegments()
   at GCHeapDumper.DumpDotNetHeapDataWorker(ClrHeap heap, ICorDebugProcess& debugProcess, Boolean isDump, Double retryScale)
   at GCHeapDumper.DumpDotNetHeapData(ClrHeap heap, ICorDebugProcess& debugProcess, Boolean isDump)
   at GCHeapDumper.TryGetDotNetDump(Int32 processID)
   at GCHeapDumper.CaptureLiveHeapDump(Int32 processID)
   at GCHeapDumper.DumpLiveHeap(Int32 processID)
   at Program.MainWorker(String[] args)


Completed: Dumping GC Heap to c:\temp\20190613.gcDump   (Elapsed Time: 1071.709 sec)
Error: HeapDump failed with exit code 1

</issue_description>

Comments on the Issue (you are @copilot in this section)

Custom agent used: Issue Triager
Investigates, reproduces, and fixes issues in PerfView and TraceEvent.


⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

Copilot AI changed the title [WIP] Fix System.NullReferenceException while taking heap snapshot Fix NullReferenceException in SegmentedList.Add during large heap snapshots Mar 20, 2026
Copilot AI requested a review from brianrob March 20, 2026 22:43
@brianrob brianrob force-pushed the copilot/fix-nullreferenceexception-heap-snapshot branch from c5fc80f to adabae6 Compare March 28, 2026 01:19
…pshots

SegmentedMemoryStreamWriter.Clear() was replacing the backing bytes list
with a brand-new empty SegmentedList, discarding the pre-allocated buffer
(potentially ~1GB for 128M-node graphs). The replacement started with
items=null and capacity=0, requiring re-growth from scratch under extreme
memory pressure, which caused NullReferenceException in SegmentedList.Add.

The fix resets bytes.Count to 0 instead, preserving the pre-allocated
segments. This is safe because SegmentedList.Add() checks count < capacity
and writes directly into existing segments. This pattern is already used
in Graph.ClearWorker() (m_nodes.Count = 0, m_types.Count = 0).

Also fixes a segment-size inconsistency: the constructor used 65_536 but
the old Clear() was creating a new list with 131_072.

Fixes #951

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@brianrob brianrob force-pushed the copilot/fix-nullreferenceexception-heap-snapshot branch from adabae6 to 7b47692 Compare March 28, 2026 01:26
@brianrob
Copy link
Copy Markdown
Member

This does not look to be complete.

@brianrob brianrob closed this Mar 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

System.NullReferenceException while taking heap snapshot

2 participants