-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CollectionView Windows Memory Leak, Android Laggy scrolling #13557
Comments
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
I debugged this app quite a bit today, I believe there are two core problems here:
I will investigate this further and let the right team know.
maui/src/Controls/src/Core/VisualElement.cs Lines 252 to 265 in 7f3b34f
Can be reproduced in a test: [Theory]
[InlineData(typeof(ImmutableBrush), false)]
[InlineData(typeof(SolidColorBrush), false)]
[InlineData(typeof(LinearGradientBrush), true)]
[InlineData(typeof(RadialGradientBrush), true)]
public async Task BackgroundDoesNotLeak(Type type, bool defaultCtor)
{
var brush = defaultCtor ?
(Brush)Activator.CreateInstance(type) :
(Brush)Activator.CreateInstance(type, Colors.CornflowerBlue);
var reference = new WeakReference(new VisualElement { Background = brush });
await Task.Yield();
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.False(reference.IsAlive, "VisualElement should not be alive!");
} Only I'll keep working on this. 👍 |
@jonathanpeppers hi. Thanks for digging into it. Regarding first problem, I am surprised, as I didn't expect that hot reload could cause issues in Release mode. |
I was testing in Debug mode, so I could do things like put breakpoints in MAUI. |
Fixes: dotnet#12344 Fixes: dotnet#13557 Context: https://github.com/dotnet-presentations/dotnet-maui-workshop While testing the `Monkey Finder` sample, I found the following scenario causes an issue: 1. Declare a `{StaticResource}` `Brush` at the `Application` level, with a lifetime of the entire application. 2. Set `Background` on an item in a `CollectionView`, `ListView`, etc. 3. Scroll a lot, navigate away, etc. 4. The `Brush` will hold onto any `View`'s indefinitely. The core problem here being `VisualElement` does: void NotifyBackgroundChanges() { if (Background is ImmutableBrush) return; if (Background != null) { Background.Parent = this; Background.PropertyChanged += OnBackgroundChanged; if (Background is GradientBrush gradientBrush) gradientBrush.InvalidateGradientBrushRequested += InvalidateGradientBrushRequested; } } If no user code sets `Background` to `null`, these events remain subscribed. To fix this: 1. Create a `WeakNotifyCollectionChangedProxy` type for event subscription. 2. Don't set `Background.Parent = this` ~~ General Cleanup ~~ Through doing other fixes related to memory leaks & C# events, we've started to gain a collection of `WeakEventProxy`-related types. I created some core `internal` types to be reused: * `abstract WeakEventProxy<TSource, TEventHandler>` * `WeakNotifyCollectionChangedProxy` The following classes now make use of these new shared types: * `BindingExpression` * `BindableLayout` * `ListProxy` * `VisualElement` This should hopefully reduce mistakes and reuse code in this area. ~~ Concerns ~~ Since, we are no longer doing: Background.Parent = this; This is certainly a behavior change. It is now replaced with: SetInheritedBindingContext(Background, BindingContext); I had to update one unit test that was asserting `Background.Parent`, which can assert `Background.BindingContext` instead. As such, this change is definitely sketchy and I wouldn't backport to .NET 7 immediately. We might test it out in a .NET 8 preview first.
@jonathanpeppers if you find a workaround, that could fix an issue, before fix will be merged into .NET 7 MAUI, please, let me know. |
Fixes: dotnet#12344 Fixes: dotnet#13557 Context: https://github.com/dotnet-presentations/dotnet-maui-workshop While testing the `Monkey Finder` sample, I found the following scenario causes an issue: 1. Declare a `{StaticResource}` `Brush` at the `Application` level, with a lifetime of the entire application. 2. Set `Background` on an item in a `CollectionView`, `ListView`, etc. 3. Scroll a lot, navigate away, etc. 4. The `Brush` will hold onto any `View`'s indefinitely. The core problem here being `VisualElement` does: void NotifyBackgroundChanges() { if (Background is ImmutableBrush) return; if (Background != null) { Background.Parent = this; Background.PropertyChanged += OnBackgroundChanged; if (Background is GradientBrush gradientBrush) gradientBrush.InvalidateGradientBrushRequested += InvalidateGradientBrushRequested; } } If no user code sets `Background` to `null`, these events remain subscribed. To fix this: 1. Create a `WeakNotifyCollectionChangedProxy` type for event subscription. 2. Don't set `Background.Parent = this` ~~ General Cleanup ~~ Through doing other fixes related to memory leaks & C# events, we've started to gain a collection of `WeakEventProxy`-related types. I created some core `internal` types to be reused: * `abstract WeakEventProxy<TSource, TEventHandler>` * `WeakNotifyCollectionChangedProxy` The following classes now make use of these new shared types: * `BindingExpression` * `BindableLayout` * `ListProxy` * `VisualElement` This should hopefully reduce mistakes and reuse code in this area. ~~ Concerns ~~ Since, we are no longer doing: Background.Parent = this; This is certainly a behavior change. It is now replaced with: SetInheritedBindingContext(Background, BindingContext); I had to update one unit test that was asserting `Background.Parent`, which can assert `Background.BindingContext` instead. As such, this change is definitely sketchy and I wouldn't backport to .NET 7 immediately. We might test it out in a .NET 8 preview first.
@alfamizar in the example above, you could avoid using |
Description
I noticed huge memory leak in my app, but seems this is widely spread issue, as it is easy to reproduce even in Monkey Finder
https://github.com/dotnet-presentations/dotnet-maui-workshop.git
Also, scrolling performance is bad on Samsung Galaxy S20 Ultra (12GB RAM) if Data Tepmplate contains Frame, without wrapping with a Grid. (I mean fixing Memory leak on Windows, ruins scrolling performance (by potentional memory) on Android)
Steps to Reproduce
Link to public reproduction project repository
https://github.com/dotnet-presentations/dotnet-maui-workshop.git
Version with bug
7.0 (current)
Last version that worked well
Affected platforms
Android, Windows
Affected platform versions
Android 9, 12; Windows 11
Did you find any workaround?
Workaround for Windows memory leak is simple. Remove Grid, that wraps Frame
Using this fix for Windows works fine
But reduces scrolling performance on Android, and may be causing memory leak (I can not check it for sure)
Relevant log output
No response
The text was updated successfully, but these errors were encountered: