dotnet / dotnet/maui

Label is retained in memory when bound to a shared FormattedString

Open
#36,320 2 comments 1 reaction 0 assignees View on GitHub
area-controls-label partner/syncfusion s/triaged s/verified
Dominant language
C#
Stars
23.3k
Forks
2k
Avg merge
1d 15h
Merged PRs (30d)
290

Description

### Description

When a Label is assigned a shared or long-lived FormattedString (for example, from `App.Resources` or a view model), the Label is not garbage collected after it becomes unreachable.

### Expected Behavior:

A Label should be eligible for garbage collection once there are no remaining application references to it, even if the assigned FormattedString is shared or long-lived.

### Actual Behavior:

The Label remains alive because the shared FormattedString continues to hold strong event subscriptions to it, resulting in a memory leak.

### Steps to Reproduce:

1. Create a shared or long-lived FormattedString.
2. Add one or more Span objects to the FormattedString.
3. Create a Label and assign the shared FormattedString to its FormattedText property.
4. Remove all application references to the Label so it becomes unreachable.
5. Force garbage collection.
6. Observe that the Label is not garbage collected because it is still referenced by the shared FormattedString through strong event subscriptions.

```[Fact, Category(TestCategory.Memory)]
public async Task LabelIsNotKeptAliveBySharedFormattedText()
{
var formattedString = new FormattedString();
formattedString.Spans.Add(new Span { Text = "Hello" });

WeakReference CreateReference()
{
var label = new Label { FormattedText = formattedString };
return new(label);
}

WeakReference reference = CreateReference();

await TestHelpers.Collect();

Assert.False(await reference.WaitForCollect(), "Label should not be alive!");

// Ensure the shared FormattedString isn't collected during the test
GC.KeepAlive(formattedString);
}

Contributor guide

Open the contributing guide

Research direction

Start with the LabelIsNotKeptAliveBySharedFormattedText test shown in the issue and run it with the memory-test category. Trace how Label assigns the shared FormattedString and how Span or FormattedString event subscriptions are removed. Done means the test observes that the Label is collected while the shared FormattedString remains alive.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
mobile-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.