Skip to content

Change MS.Internal.Span (ItemSpan.h) to value struct to reduce text related internal allocations#11747

Open
nietras wants to merge 3 commits into
dotnet:mainfrom
nietras:itemspan-struct
Open

Change MS.Internal.Span (ItemSpan.h) to value struct to reduce text related internal allocations#11747
nietras wants to merge 3 commits into
dotnet:mainfrom
nietras:itemspan-struct

Conversation

@nietras

@nietras nietras commented Jul 2, 2026

Copy link
Copy Markdown

For years I have observed MS.Internal.Span turn up as top 10 object being allocated in WPF app. Here I suggest to finally address this by turning the very small and simple Span(object element, int length) into a value type instead of reference type to reduce GC pressure and total memory use. I do not know how WPF does benchmarks or what metric is used to verify this change. I understand it changes a long standing internal type and hope the work is not seen as futile or irrelevant.

Example object allocation count for a WPF app that continuously updates simple TextBlocks with counts or similar. Span is almost always number one in any of our WPF apps. With other WPF allocs top too. Perhaps if this PR is accepted those can be addressed too.

image

Description

Changes internal Span type from reference type to value to reduce text related managed heap allocations and GC pressure. To ensure correctness type also changed to readonly/initonly and minor necessary related code changed related to this.

Customer Impact

Reduced GC pressure.

Risk

Minor breaking internal change which may cause unexpected usage or similar.

Microsoft Reviewers: Open in CodeFlow

@nietras nietras requested review from a team and Copilot July 2, 2026 16:58
@nietras nietras requested a review from a team as a code owner July 2, 2026 16:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 reduces GC pressure in WPF text-related code paths by changing the internal MS.Internal.Span (defined in ItemSpan.h) from a reference type to a value type, and updating surrounding APIs/call sites to preserve correctness under value-type copy semantics.

Changes:

  • Converted Span in the DirectWrite forwarder layer from ref struct to value struct (with initonly fields) and updated related IList<Span>-based APIs.
  • Added/used “set-in-place” APIs (SetAt) so callers can replace spans in backing vectors/lists when lengths change (instead of mutating a referenced object).
  • Updated text formatting code (TextStore, SpanVector) to rebuild-and-store updated spans rather than mutating fields on a shared reference.

Reviewed changes

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

Show a summary per file
File Description
src/Microsoft.DotNet.Wpf/src/Shared/MS/Utility/FrugalList.cs Adds SetAt to support replacing items in frugal storage (needed for value-type spans).
src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/TextStore.cs Replaces span mutation with “recreate + SetAt” to handle value-type span updates.
src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Span.cs Updates span vector logic for value-type semantics and exposes SetAt on SpanVector.
src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextItemizer.h Updates itemizer API to return IList<Span> instead of IList<Span^>.
src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextItemizer.cpp Updates list element creation to add Span values (not heap-allocated Span^).
src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.h Updates analyzer APIs to return IList<Span> instead of IList<Span^>.
src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp Updates analyzer implementation and exception strings for the new Span value type.
src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/ItemSpan.h Converts Span to a value struct and makes fields initonly to enforce immutability.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Microsoft.DotNet.Wpf/src/Shared/MS/Utility/FrugalList.cs
Comment thread src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Span.cs
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@gpaskaleva-msft gpaskaleva-msft added API suggestion Early API idea and discussion, it is NOT ready for implementation API Change and removed API suggestion Early API idea and discussion, it is NOT ready for implementation labels Jul 3, 2026
@amarinov-msft amarinov-msft added the PR metadata: Label to tag PRs, to facilitate with triage label Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API Change PR metadata: Label to tag PRs, to facilitate with triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants