Change MS.Internal.Span (ItemSpan.h) to value struct to reduce text related internal allocations#11747
Open
nietras wants to merge 3 commits into
Open
Change MS.Internal.Span (ItemSpan.h) to value struct to reduce text related internal allocations#11747nietras wants to merge 3 commits into
nietras wants to merge 3 commits into
Conversation
…elated internal allocations
Contributor
There was a problem hiding this comment.
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
Spanin the DirectWrite forwarder layer fromref structtovalue struct(withinitonlyfields) and updated relatedIList<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.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For years I have observed
MS.Internal.Spanturn up as top 10 object being allocated in WPF app. Here I suggest to finally address this by turning the very small and simpleSpan(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.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