Skip to content

[Perf] Reduce allocations in inherited BindingContext propagation - #34135

Closed
simonrozsival wants to merge 3 commits into
net11.0from
dev/simonrozsival/bindingcontext-allocs
Closed

[Perf] Reduce allocations in inherited BindingContext propagation#34135
simonrozsival wants to merge 3 commits into
net11.0from
dev/simonrozsival/bindingcontext-allocs

Conversation

@simonrozsival

Copy link
Copy Markdown
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Fixes #34129

Description

Two allocation reductions on the hot SetInheritedBindingContext path (called recursively for every descendant when BindingContext changes):

1. Reuse existing WeakReference

Instead of new WeakReference(value) on every descendant, reuse the existing WeakReference by updating its .Target property.

2. Eliminate .ToArray() in ApplyBindings

ApplyBindings was calling .ToArray() on the properties dictionary values before iterating. Since ApplyBinding only reads bindings and does not modify the dictionary, direct foreach iteration is safe and avoids the array allocation.

simonrozsival and others added 2 commits March 11, 2026 10:32
Fixes #34129

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/bindingcontext-allocs branch from 6453f68 to dcd3a94 Compare March 11, 2026 09:32
@github-actions

github-actions Bot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34135

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34135"

@simonrozsival
simonrozsival marked this pull request as ready for review March 11, 2026 10:38
Copilot AI review requested due to automatic review settings March 11, 2026 10:38
@simonrozsival simonrozsival changed the title [WIP][Perf] Reduce allocations in inherited BindingContext propagation [Perf] Reduce allocations in inherited BindingContext propagation Mar 11, 2026

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 targets a hot path in the Controls binding engine (BindableObject.SetInheritedBindingContext) to reduce per-element allocations when BindingContext propagates down the visual tree.

Changes:

  • Reuse an existing _inheritedContext WeakReference by updating .Target instead of allocating a new instance each time.
  • Remove the _properties.Values.ToArray() snapshot in ApplyBindings and enumerate _properties.Values directly.

Comment thread src/Controls/src/Core/BindableObject.cs Outdated
var prop = _properties.Values.ToArray();

for (int i = 0, propLength = prop.Length; i < propLength; i++)
foreach (var context in _properties.Values)

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

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

Iterating directly over _properties.Values here is not safe: ApplyBinding ultimately calls into BindingBase.Apply/BindingExpression.ApplyCore, which can invoke SetValueCore and property-changed callbacks. Those callbacks can add/remove bindable property contexts (modifying _properties) and will cause the dictionary enumerator to throw InvalidOperationException mid-iteration. The previous ToArray() snapshot avoided this; consider keeping a snapshot (potentially via pooled/rented array) or using a guarded pattern (e.g., retry or fallback snapshot when a modification is detected) so BindingContext propagation can’t crash on re-entrant property changes.

Suggested change
foreach (var context in _properties.Values)
var contexts = _properties.Values.ToArray();
foreach (var context in contexts)

Copilot uses AI. Check for mistakes.
Comment thread src/Controls/src/Core/BindableObject.cs Outdated
var prop = _properties.Values.ToArray();

for (int i = 0, propLength = prop.Length; i < propLength; i++)
foreach (var context in _properties.Values)

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

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

This change alters ApplyBindings iteration semantics in a way that can be sensitive to re-entrant property changes. It would be helpful to add a unit test which triggers a binding application that, via a propertyChanged callback (or similar), adds/removes a different BindableProperty context while ApplyBindings is running, and asserts no InvalidOperationException is thrown.

Suggested change
foreach (var context in _properties.Values)
// Take a snapshot of the current property contexts so that re-entrant
// modifications to the _properties collection (e.g., via propertyChanged
// callbacks triggered during ApplyBinding) do not invalidate the enumerator.
var propertyContexts = _properties.Values.ToArray();
foreach (var context in propertyContexts)

Copilot uses AI. Check for mistakes.
ApplyBinding can trigger property-changed callbacks that modify
_properties mid-iteration. Keep the snapshot to avoid
InvalidOperationException. Added explanatory comment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
Member Author

Closing — after reverting the unsafe ToArray removal, the remaining WeakReference reuse alone isn't impactful enough to justify the PR. May revisit as part of a broader BindingContext optimization effort.

@github-actions github-actions Bot locked and limited conversation to collaborators Apr 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot perf/general The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants