[leak-scan] VisualElement.Resources roots discarded controls via shared dictionary
- Dominant language
- C#
- Stars
- 23.3k
- Forks
- 2k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 290
Description
`VisualElement.Resources` strongly subscribes each visual element to the assigned dictionary's internal `ValuesChanged` event. A long-lived/shared `ResourceDictionary` therefore retains discarded controls even when they never enter a visual tree or acquire a handler.
**Empirical result**
A standalone `net10.0` xUnit test referencing shipped `Microsoft.Maui.Controls` **10.0.0** created 30 subjects, each holding a 1 MiB payload:
| Scenario | Payloads alive after 7 full GC cycles |
|---|---:|
| Control (never assigns shared dictionary) | 0/30 |
| Leaky (assigns shared dictionary) | 30/30 |
| Mitigation (replaces it with a fresh dictionary) | 0/30 |
Core test setup:
```csharp
var shared = new ResourceDictionary();
// Repeated 30 times; PayloadProperty contains a new 1 MiB byte[] tracked by WeakReference.
var label = new Label();
label.SetValue(PayloadProperty, payload);
label.Resources = shared;
// Mitigation variant:
label.Resources = new ResourceDictionary();
```
Retention path:
`shared ResourceDictionary -> ValuesChanged delegate -> VisualElement.OnResourcesChanged -> discarded Label -> attached payload`
The current source attaches the strong handler at `src/Controls/src/Core/VisualElement/VisualElement.cs:1170-1190`; replacing the dictionary unsubscribes the old one and releases all mitigation subjects.
Expected behavior: assigning a shared resource dictionary should not permanently root otherwise-unreachable visual elements, or the subscription needs lifecycle teardown when the element is discarded/removed.
This issue was generated by the Daily Memory Leak Hunter workflow using an empirical shipped-package test. No MAUI source build, platform handler, emulator, or native peer was involved.
> Generated by [Daily Memory Leak Hunter](https://github.com/dotnet/maui/actions/runs/34124516166) · gpt56 · 213.6 AIC · ⌖ 12.3 AIC · ⊞ 32.2K · [◷](https://github.com/search?q=repo%3Adotnet%2Fmaui+is%3Aissue+%22gh-aw-workflow-call-id%3A+dotnet%2Fmaui%2Fdaily-leak-hunter%22&type=issues)
Contributor guide
Research direction
Start in src/Controls/src/Core/VisualElement/VisualElement.cs:1170-1190 and run the standalone net10.0 xUnit reproduction described in the issue. Trace the shared ResourceDictionary subscription and its teardown behavior. Done means discarded controls assigned a shared dictionary are no longer retained, with the GC-based reproduction confirming payloads are collectible.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100