Implement opt-in weak reference handling for ElementProxy in automation peers to mitigate memory leaks in virtualized ItemsControls#11638
Open
amarinov-msft wants to merge 2 commits into
Conversation
…on peers to mitigate memory leaks in virtualized ItemsControls
Author
|
@dotnet-policy-service agree company="Microsoft" |
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an opt-in AppContext switch to allow ElementProxy to hold ItemAutomationPeer (and subclasses) via WeakReference, reducing managed-heap retention/leaks in virtualized ItemsControl automation scenarios when UIA Core retains ElementProxy instances longer than expected.
Changes:
- Introduces a new internal virtual
AutomationPeer.ShouldUseWeakReferenceFromElementProxyhook (defaultfalse). - Overrides the hook in
ItemAutomationPeerto read a new opt-in AppContext switch. - Extends
ElementProxy’s weak-reference selection logic to include peers opting in via the new hook.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Automation/Peers/ItemAutomationPeer.cs | Overrides the new hook to opt ItemAutomationPeer into weak-referencing based on the AppContext switch. |
| src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/FrameworkAppContextSwitches.cs | Defines the new AppContext switch used to gate the behavior. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs | Adds the internal virtual hook to allow peers to opt in. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/ElementProxy.cs | Uses the new hook to decide when to store the peer as a WeakReference. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+158
to
+164
| // Gated by FrameworkAppContextSwitches.UseWeakReferenceFromElementProxyToItemPeer. When on, | ||
| // a long-lived UIA ElementProxy no longer pins the data item, container, or parent | ||
| // ItemsControlAutomationPeer caches; re-discovery goes via WeakRefElementProxyStorage on the parent. | ||
| internal override bool ShouldUseWeakReferenceFromElementProxy | ||
| { | ||
| get { return FrameworkAppContextSwitches.UseWeakReferenceFromElementProxyToItemPeer; } | ||
| } |
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.
Fixes #11337
Main PR
Description
UIA Core retains
ElementProxyinstances longer than WPF expects. SinceElementProxyheldItemAutomationPeervia a strong reference, this pinned the data item, the container, and the parentItemsControlAutomationPeer's caches - manifesting as large managed-heap growth in virtualizedItemsControls (DataGrid,TreeView, etc.).This PR extends the existing
WeakReferencelifetime model — already used forUIElement,ContentElement, andUIElement3DAutomationPeer- toItemAutomationPeerand its subclasses. Peer re-discovery after collection is preserved by the parentItemsControlAutomationPeer'sWeakRefElementProxyStorage, so the UIA tree remains correct: UIA clients receiveElementNotAvailableExceptionand re-walk as they already do forUIElement-derived peers.The behavior is gated by a new opt-in AppContext switch (
Switch.System.Windows.Automation.Peers.UseWeakReferenceFromElementProxyToItemPeer), default off, so no existing application is affected unless it explicitly opts in.Customer Impact
Currently it is not possible to test WPF/WinForms application with UI Automation in a leak-free way. This prevents early detection of memory leaks.
Regression
No
Testing
Risk
Low overall, because the change is opt-in and default-off behind a new AppContext switch
(
Switch.System.Windows.Automation.Peers.UseWeakReferenceFromElementProxyToItemPeer).Default behavior (switch off)
No code path changes.
ElementProxystill holdsItemAutomationPeerstrongly. The only added cost is one virtual property read in theElementProxyconstructor, which returnsfalseon the baseAutomationPeerand is hit only whenAutomationInteropReferenceType == ReferenceType.Weak.Opt-in behavior (switch on)
ItemAutomationPeeradopts the same lifetime model already used byUIElement,ContentElement, andUIElement3DAutomationPeer. Specifically:ItemsControlAutomationPeer'sWeakRefElementProxyStorage- the same mechanism that already supports theUIElement-derived peers under the existingWeakreference mode.ElementNotAvailableExceptionand re-walk, which is documented and expected UIA behavior.Scope of change
AutomationPeer(defaultfalse).ItemAutomationPeerthat reads the switch.ElementProxyconstructor.No public API changes. All new members are
internal.Residual risks considered
WeakRefElementProxyStorage; requires validation, but the recovery path is the same oneUIElementAutomationPeeralready relies on.ItemAutomationPeerderivatives (DataGridItemAutomationPeer, DataGridCellItemAutomationPeer,DateTimeAutomationPeer,TreeViewDataItemAutomationPeer`, etc.) automatically inherit the new behavior, which is the intent.Microsoft Reviewers: Open in CodeFlow