adamessenmacher / memorytoolkit.maui Goto Github PK
View Code? Open in Web Editor NEWA developer toolkit for detecting, diagnosing, and mitigating memory leaks in .NET MAUI applications.
License: MIT License
A developer toolkit for detecting, diagnosing, and mitigating memory leaks in .NET MAUI applications.
License: MIT License
If a label uses spans in the formatted string, it doesn't seem to register it as children on the element.
<Label
MaxLines="2"
LineBreakMode="WordWrap"
VerticalOptions="Center">
<Label.FormattedText>
<FormattedString>
<Span Text="Text One" />
<!--Add blank space between normal text and link text-->
<Span Text=" " />
<Span Text="Text Two" TextDecorations="Underline">
<Span.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CommandHere}" />
</Span.GestureRecognizers>
</Span>
</FormattedString>
</Label.FormattedText>
</Label>
Therefore, the spans are not getting cleared in TearDownImpl
.
Adding the following seems to work.
if (vte is Label label)
{
if (label.FormattedText != null)
{
TearDownImpl(label.FormattedText);
}
}
Happy to discuss further if required.
Hi Adam, thanks for creating this utility - I've added into my project, and it is successfully detecting leaks, but they aren't being removed - not sure if there is any thing additional that I need to do?
I have the following hierarchy (simplified):
Content View (SearchView)
Content View (OtherViews)
Content View (OtherViews)
Content View (OtherViews)
Essentially, I am getting a list of search results (Profiles), creating a custom view (ProfileView) and adding it to the SearchView one by one. One profile is created and the user presses a button which removes the current ProfileView from the screen and then creates a new one.
I've added in your code snippets into the content view (ProfileView) and enabled the App.xaml to ShowMemToolkitAlerts. It is successfully detecting leaks when the ProfileView is removed from the screen. However, the memory heap size keeps increasing and the Leaks detected continues to increase when removing current profileview and adding a new one.
Is there something else that I need to do to remove this?
First, awesome job! We discovered your package after we discovered a memory leak. And as it happens, the leak itself was related to pushing/popping pages off the stack - the page wasn't be disposed properly. We are targeting Windows only (ATM) but likely to have Android release in future.
The suggestion I have is: clear the binding context before you disconnect the layouts. The reason is that if you use two-way binding, the backing viewmodel reset it's properties back to default (and that wasn't the behavior we were looking for). The proposed fix would be to modify AutoDisconnectBehavior.cs and move line 164 to line 151.
Thanks again!
Was wanting to check this out and upon trying to build seems the Utilities class is missing?
E.x.
var hostPage = Utilities.GetFirstSelfOrParentOfType<Page>(visualElement);
Hi Adam! Great work on this repo, are you planning to release a Nuget Package for an easier setup and installation soon?
Best regards
First of all, thanks for this project. It helps identify issues massively!
I noticed that whilst the page is cleared down much better, our view models were not getting cleaned out. Doing some digging, it seems that tap gesture recognizers keep their reference and aren't cleared.
Adding the following snippet helped clear these instances that were not previously.
if (vte is IGestureRecognizers gr)
{
gr.GestureRecognizers.Clear();
}
I have not raised a PR as you may not choose use to it and/or have alternate ideas based on this.
Happy to discuss more.
I set up a minimal sample that is pretty close to my real application. It seemed like it worked in the sample app that it would wait for the pop before executing the tear down. However if you look at this it is tearing down my "equipmentlistpage" once it arrives on "equipmentdetailpage".
Reproduction Repo:
https://github.com/mruncola/DotnetMauiMemoryCrash
I added a toggle to change the navigation mechanism under the hood to use goto and push pop so you can see they both have similar results.
Push / Pop ----
Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.ElementForViewController(UIViewController viewController)
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.NavDelegate.WillShowViewController(UINavigationController navigationController, UIViewController viewController, Boolean animated)
--- End of stack trace from previous location ---
at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/ObjCRuntime/Runtime.cs:line 2594
at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 60
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 94
at SadMemory.Program.Main(String[] args) in /DotnetMauiMemoryCrash/SadMemory/Platforms/iOS/Program.cs:line 13
2024-04-23 15:28:21.657004-0400 SadMemory[37997:4033394] Unhandled managed exception: Object reference not set to an instance of an object. (System.NullReferenceException)
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.ElementForViewController(UIViewController viewController)
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.NavDelegate.WillShowViewController(UINavigationController navigationController, UIViewController viewController, Boolean animated)
--- End of stack trace from previous location ---
at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/ObjCRuntime/Runtime.cs:line 2594
at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 60
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 94
at SadMemory.Program.Main(String[] args) in /DotnetMauiMemoryCrash/SadMemory/Platforms/iOS/Program.cs:line 13
GoTo ----
2024-04-23 15:09:51.402746-0400 SadMemory[36835:4004936]
Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.ElementForViewController(UIViewController viewController)
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.NavDelegate.WillShowViewController(UINavigationController navigationController, UIViewController viewController, Boolean animated)
--- End of stack trace from previous location ---
at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/ObjCRuntime/Runtime.cs:line 2594
at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 60
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 94
at SadMemory.Program.Main(String[] args) in /DotnetMauiMemoryCrash/SadMemory/Platforms/iOS/Program.cs:line 13
2024-04-23 15:09:51.403406-0400 SadMemory[36835:4004936] Unhandled managed exception: Object reference not set to an instance of an object. (System.NullReferenceException)
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.ElementForViewController(UIViewController viewController)
at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.NavDelegate.WillShowViewController(UINavigationController navigationController, UIViewController viewController, Boolean animated)
--- End of stack trace from previous location ---
at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/ObjCRuntime/Runtime.cs:line 2594
at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 60
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 94
at SadMemory.Program.Main(String[] args) in /DotnetMauiMemoryCrash/SadMemory/Platforms/iOS/Program.cs:line 13
Needed to add a try/catch around certain calls within DisconnectImpl(). The offending culprit in this case is the SyncFusion ListView control. The exception shows a NullReferenceException happening deep in their code. I'll report this to SyncFusion as well.
04-22 18:43:17.661 [-DBG-1] TrySafe:Exception in DisconnectImpl (Disconnect Handler Syncfusion.Maui.ListView.ListViewEmptyViewItem): System.NullReferenceException: Object reference not set to an instance of an object.
at Syncfusion.Maui.ListView.ListViewItemExtensions.WireEvents(ListViewItem listViewItem)
at Syncfusion.Maui.ListView.ListViewItem.OnHandlerChanged()
at Microsoft.Maui.Controls.VisualElement.OnHandlerChangedCore()
at Microsoft.Maui.Controls.Element.SetHandler(IElementHandler newHandler)
at Microsoft.Maui.Handlers.ElementHandler.DisconnectHandler(Object platformView)
at Microsoft.Maui.Handlers.ElementHandler.Microsoft.Maui.IElementHandler.DisconnectHandler()
at Mobile.Framework.NavigatorUtilities.<>c__DisplayClass0_0.<Disconnect>b__7()
at Mobile.Framework.NavigatorUtilities.<Disconnect>g__TrySafely|0_0(Action action, String msg)
void TrySafely(Action action, string? msg = null)
{
try { action.Invoke();} catch (Exception e)
{
Serilog.Log.Logger.Verbose($"TrySafe:Exception in DisconnectImpl ({msg}): {e}");
}
}
TrySafely(() => { visualElement.Handler?.DisconnectHandler(); }, $"Disconnect Handler {visualElement}");
Hi Adam, thanks for building this! I'm having trouble writing the equivilent C# for the XAML you provided to wire up a ContentPage. Could you point me in the right direction?
I have a collection view that was not getting cleared correctly in tear down.
A CollectionView
is not of type ListView
, so the area of code that clears a list views item source wasn't being hit.
I think this could change to use the common underlying structure ItemsView
, which has ItemsSource
and ItemTemplate
. This then would clear down collection view and list views correctly, along with some other controls that likely inherit ItemsView
.
I therefore propose the following:
if (vte is ListView listView)
listView.ItemsSource = null;
becomes:
if (vte is ItemsView itemsView)
{
itemsView.ItemsSource = null;
itemsView.ItemTemplate = null;
}
This seems to sort the issue out for me.
If a visual element has any behaviours on it, it is not getting cleared. This can lead to the entire page and view models etc not being garbage collected.
Adding the following makes it work for me in tear down.
visualElement.Behaviors.Clear();
Happy to discuss further.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.