Skip to content
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

Memory leaks EVERYWHERE #12039

Closed
Vroomer opened this issue Dec 12, 2022 · 44 comments · Fixed by #13327
Closed

Memory leaks EVERYWHERE #12039

Vroomer opened this issue Dec 12, 2022 · 44 comments · Fixed by #13327
Assignees
Labels
delighter fixed-in-8.0.0-preview.1.7762 Look for this fix in 8.0.0-preview.1.7762! legacy-area-perf Startup / Runtime performance p/0 Work that we can't release without partner/cat 😻 this is an issue that impacts one of our partners or a customer our advisory team is engaged with platform/windows 🪟 t/bug Something isn't working t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.)
Milestone

Comments

@Vroomer
Copy link

Vroomer commented Dec 12, 2022

Description

I'm trying to develop LoB app in MAUI, including lot's of CollectionViews and complex master-details with multiple views, data forms and custom controls. It's bumpy road, but by far the most critical issue for me is the amount of memory leaks, which makes the app completely unusable.

742nlk

I have already reported 2 issues resulting in severe memory leak and there have been many more raised over time by others. Unfortunately they aren't getting attention they deserve in my opinion.

The more I look into this topic, the more puzzled I'm by memory management in MAUI and the more I'm determined that there is something horribly wrong happening inside MAUI. I decided to create another sample to demonstrate this issue and it's significance for production apps. The sample is very simple MVVM app with CollectionView of Items. Clicking on an item will bring you to a detail page.

This bit in DetailPage constructor was added to increase memory allocation of the detail to make the memory leak more obvious (Array.Clear(Bytes) causes array to be iterated and allocated):

        Bytes = new byte[1024 * 400000];
        Array.Clear(Bytes); 

If you keep navigating back and forth from master to its details and watch memory usage, you will see memory raising from 100 MBs to several GBs very quickly. I added button to execute GC.Collect(), but forcing GC never disposes all the resources.
image

Calling this to manually free some resources doesn't seem to have any effect.

		vm.Bytes = null;
		vm.Item = null;
		BindingContext = null;

I made several observations:

  • Memory doesn't always go up upon opening the DetailPage.
  • GC sometimes does seem to be able to dispose some resources.
  • Using VS memory profiler, I don't see my objects bloating the memory.
  • Using VS memory profiler, I see lot's of UI bits and handlers being stuck in the memory.
  • There seem to be no single point of root holding these things.
  • Seems like xaml bindings might have something to do with it.

image

The issue is obvious in other samples as well, for example Monkey app by @jamesmontemagno
https://github.com/dotnet-presentations/dotnet-maui-workshop

Note that there is no use of static resources or event subscription anywhere in the sample code.

I observed the issue only in Windows as I have no sufficient way to check memory in other platforms.

Any tips about how to dispose DetailPage with all the related resources would be very welcomed.

Steps to Reproduce

  1. Load the repository and run the app.
  2. Repeatedly open details from CollectionView by selecting them and then pop the DetailPage using the button while observing memory usage in ResMon/memory profiler.
  3. Click on the "Force GC" button to trigger GC - some memory resources might be disposed, but the memory leak persists.

Link to public reproduction project repository

https://github.com/Vroomer/MAUI-master-detail-memory-leak.git

Version with bug

7.0 (current)

Last version that worked well

Unknown/Other

Affected platforms

Windows, I was not able test on other platforms

Affected platform versions

Windows SDK 10.0.22000

Did you find any workaround?

No response

Relevant log output

No response

@Vroomer Vroomer added the t/bug Something isn't working label Dec 12, 2022
@jsuarezruiz jsuarezruiz added the legacy-area-perf Startup / Runtime performance label Dec 13, 2022
@8m0
Copy link

8m0 commented Dec 13, 2022

If you keep navigating back and forth from master to its details and watch memory usage, you will see memory raising

Hi, the problem exists since Xamarin. And you can find similar bug reports for MAUI. I think this problem will be moved to "Backlog milestone" as always.

I remember that result can differ from debug and release. So you can test it on release version just to be sure.

@angelru

This comment was marked as off-topic.

@8m0

This comment was marked as off-topic.

@wubalubadubdub55
Copy link

I have the same problem. cc: @PureWeen

@mohachouch
Copy link
Contributor

mohachouch commented Dec 13, 2022

@jsuarezruiz @PureWeen @jamesmontemagno @maddymontaquila @davidortinau same problem on Xamarin Forms

We spent 3 weeks, 2 developers trying to figure out why the pages are not cleaning up. Unable to find. We just see in the Xamarin Profiler that the Resource Dictionary memory increases

@ghost
Copy link

ghost commented Dec 13, 2022

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.

@samhouts samhouts added the p/1 Work that is important, and has been scheduled for release in this or an upcoming sprint label Dec 17, 2022
@mohachouch

This comment was marked as off-topic.

@PureWeen
Copy link
Member

PureWeen commented Jan 8, 2023

related #12344

@nk54
Copy link

nk54 commented Jan 12, 2023

From @8m0

I think this problem will be moved to "Backlog milestone" as always.

This one made me laugh more than expected after I saw the bot moving this thread to the backlog milestone

I din't expect Xamarin to be memory leak proof because it wasn't a tech from Microsoft at first. But I expected MAUI to be better. Far better than its current state about momery leaks...

@rkebelj
Copy link

rkebelj commented Jan 16, 2023

This is so sad.

@nikolaykusch
Copy link

Same problem. I have only one question. How to work with MAUI with such bugs?

@symbiogenesis
Copy link
Contributor

symbiogenesis commented Jan 23, 2023

There isn't an excuse for memory leaks on the platform, but the patterns that are likely to cause memory leaks are likely not great patterns for normal workloads. You shouldn't be abusing query parameters, for instance. And the leaks aren't any worse than Xamarin.Forms was. In my case, XF was worse. Until the platform bugs are fixed, the best you can do is focus on your own code.

Events are one of the most likely causes of leaks, and those can be solved if you implement WeakEventManager. That one is pretty easy to do.

I had seen worse leaks from the handlers in XF, particularly inside of CollectionViews. You could scroll and just watch the memory usage rise and rise endlessly. I think a lot of those issues were solved with MAUI. I don't see this at all with my app.

Premature optimization is a bad idea. Unless your app has a known memory issue, there is no reason to assume that it does. For me, converting from XF to MAUI caused a measurable and dramatic decrease in memory usage.

@nikolaykusch
Copy link

nikolaykusch commented Jan 23, 2023

There isn't an excuse for memory leaks on the platform, but the patterns that are likely to cause memory leaks are likely not great patterns for normal workloads. You shouldn't be abusing query parameters, for instance. And the leaks aren't any worse than Xamarin.Forms was. In my case, XF was worse. Until the platform bugs are fixed, the best you can do is focus on your own code.

Events are one of the most likely causes of leaks, and those can be solved if you implement WeakEventManager. That one is pretty easy to do.

I had seen worse leaks from the handlers in XF, particularly inside of CollectionViews. You could scroll and just watch the memory usage rise and rise endlessly. I think a lot of those issues were solved with MAUI. I don't see this at all with my app.

Premature optimization is a bad idea. Unless your app has a known memory issue, there is no reason to assume that it does. For me, converting from XF to MAUI caused a measurable and dramatic decrease in memory usage.

In my case, this is the biggest problem with CollectionView. So much so that I'm currently trying to migrate to Uno

@angelru
Copy link

angelru commented Jan 23, 2023

No hay excusa para las fugas de memoria en la plataforma, pero los patrones que probablemente causen fugas de memoria probablemente no sean buenos patrones para las cargas de trabajo normales. No debería abusar de los parámetros de consulta, por ejemplo. Y las filtraciones no son peores que las de Xamarin.Forms. En mi caso, XF fue peor. Hasta que se corrijan los errores de la plataforma, lo mejor que puede hacer es concentrarse en su propio código.
Los eventos son una de las causas más probables de fugas y se pueden resolver si implementa WeakEventManager. Ese es bastante fácil de hacer.
Había visto filtraciones peores de los controladores en XF, particularmente dentro de CollectionViews. Puede desplazarse y simplemente ver cómo el uso de la memoria aumenta y aumenta sin cesar. Creo que muchos de esos problemas se resolvieron con MAUI. No veo esto en absoluto con mi aplicación.
La optimización prematura es una mala idea. A menos que su aplicación tenga un problema de memoria conocido, no hay razón para suponer que lo tiene. Para mí, la conversión de XF a MAUI provocó una disminución medible y dramática en el uso de la memoria.

En mi caso, este es el mayor problema de CollectionView. Tanto es así que actualmente estoy tratando de migrar a Uno

Memory and performance issues, which are related, try my sample:
#12130

Thinking of migrating to Flutter.

@Vroomer
Copy link
Author

Vroomer commented Jan 23, 2023

@symbiogenesis I have big app ready for production and I can't release it because it goes from 200 MB to 2000 MB in matter of a few minutes of using it. It's by far the biggest problem I encountered as there is no workaround. It's not data objects being stuck, it's all just UI bits being held by strong references from brushes, gesture handlers and god knows what else. The problem is really serious. No events or things like that are causing my memory leaks. I either make sure to detach events or make them as a weak reference.

@symbiogenesis
Copy link
Contributor

symbiogenesis commented Jan 24, 2023

I loaded up thousands of records into a CollectionView today, and noticed that the scrolling on WinUI was actually smooth. Android and iOS were bad.

Looks like the recent PRs #12627 and #12660 will be helping.

Some tricks to try now include:

  • Set constant and explicit heights everywhere possible
  • Set ItemSizingStrategy to MeasureFirstItem if possible
  • Set CompressedLayout.IsHeadless to true where possible
  • Set the Binding mode to OneTime where possible

These tricks are all used by @angelru already, but not everyone may be aware.

In addition to those tricks and the aforementioned WeakReferences for events, other things to try:

  • Initialize collections early all at once, if possible, instead of adding a lot of records to the public property after it is created.
  • Cache complex objects and dynamic UI objects where possible, using something like a ConcurrentDictionary

@angelru
Copy link

angelru commented Jan 24, 2023

I loaded up thousands of records into a CollectionView today, and noticed that the scrolling on WinUI was actually smooth. Android and iOS were bad.

Looks like the recent PRs #12627 and #12660 will be helping.

Some tricks to try now include:

  • Set constant and explicit heights everywhere possible
  • Set ItemSizingStrategy to MeasureFirstItem if possible
  • Set CompressedLayout.IsHeadless to true where possible
  • Set the Binding mode to OneTime where possible

These tricks are all used by @angelru already, but not everyone may be aware.

In addition to those tricks and the aforementioned WeakReferences for events, other things to try:

  • Initialize collections early all at once, if possible, instead of adding a lot of records to the public property after it is created.
  • Cache complex objects and dynamic UI objects where possible, using something like a ConcurrentDictionary
  • Use the UniformItemsLayout from CommunityToolkit.Maui instead of anything fancier if everything is the same size.

Even if in my provided example you set:
ItemSizingStrategy to MeasureFirstItem, activate AOT...

scrolling on Android/iOS is unacceptable. Try my sample.

@akhanalcs
Copy link

Any update on this serious bug?

@symbiogenesis
Copy link
Contributor

symbiogenesis commented Jan 26, 2023

Looks like this custom ListView control advertises that it avoids memory leaks

https://github.com/Keflon/FunctionZero.Maui.Controls

This one may also be useful, but only for Android and iOS:

https://github.com/roubachof/Sharpnado.CollectionView

this one also seems promising:

https://github.com/Redth/Maui.VirtualListView

@nikolaykusch
Copy link

I loaded up thousands of records into a CollectionView today, and noticed that the scrolling on WinUI was actually smooth. Android and iOS were bad.

Looks like the recent PRs #12627 and #12660 will be helping.

Some tricks to try now include:

  • Set constant and explicit heights everywhere possible
  • Set ItemSizingStrategy to MeasureFirstItem if possible
  • Set CompressedLayout.IsHeadless to true where possible
  • Set the Binding mode to OneTime where possible

These tricks are all used by @angelru already, but not everyone may be aware.

In addition to those tricks and the aforementioned WeakReferences for events, other things to try:

  • Initialize collections early all at once, if possible, instead of adding a lot of records to the public property after it is created.
  • Cache complex objects and dynamic UI objects where possible, using something like a ConcurrentDictionary
  • Use the UniformItemsLayout from CommunityToolkit.Maui instead of anything fancier if everything is the same size.

It won't help in my case. A lot of VM updates, binding - TwoWay

jonathanpeppers added a commit to jonathanpeppers/maui that referenced this issue Feb 14, 2023
Fixes: dotnet#12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

In investigating various MAUI samples, I found the following object
leaking:

    WeakPropertyChangedProxy ->
        TypedBinding
        Binding

In ~2016, I contributed a fix to Xamarin.Forms:

xamarin/Xamarin.Forms@f6febd4

Back then, this solved the follow case:

1. You have a long-lived `ViewModel` class. Could be a singleton, etc.

2. Data-bind a `View` to this `ViewModel`.

3. The `ViewModel` indefinitely held on to any object that subscribed
   to `PropertyChanged`.

At the time, this solved a huge memory leak, because a data-bound
`View` would have a reference to its parent, then to its parent, etc.
Effectively this was leaking entire `Page`'s at the time.

Unfortunately, there was still a flaw in this change...
`WeakPropertyChangedProxy` hangs around forever instead! I could
reproduce this problem in unit tests, by accessing various internal
members through reflection -- asserting they were alive or not.

We do have another layer of indirection, where other objects are GC'd
that can free the `WeakPropertyChangedProxy`, such as:

    // Regular Binding
    ~BindingExpressionPart() => _listener?.Unsubscribe();
    // TypedBinding
    ~PropertyChangedProxy() => Listener?.Unsubscribe();

This means it would take two GC's for these objects to go away, but it
is better than the alternative -- they *can* actually go away now.

After testing apps with this change, sometimes I would get an
`InvalidOperationException` in `WeakReference<T>`:

https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs,103

So I added a parameter to `Unsubscribe(finalizer: true)`, to skip
`WeakReference<T>.SetTarget()` from finalizers.

After this change, I still found an issue! In my new unit test, the
following would hold onto a `ViemModel` object forever:

    VisualElement.BackgroundProperty.DefaultValue

This held the value of `Brush.Default`, in which
`Brush.Default.BindingContext` was the `ViewModel`!

My first thought was for `Brush.Default` to return `ImmutableBrush`:

    public static Brush Default => new ImmutableBrush(null);

Because anyone could do `Brush.Default.Color = Colors.Red` if they liked.

When this didn't fix it, I found the underlying `_inheritedContext` is
what held a reference to my `ViewModel` object. I changed this value
to a `WeakReference`.

The types of leaks this fixes:

* Bindings to application-lifetime, singleton `ViewModel`s

* Scrolling `CollectionView`, `ListView`, etc. with data-bindings.

* Styles that were used on a `View` or `Page` that is now removed from
  the screen via navigation, de-parenting, etc.

Ok, I really think the leaks are gone now. Maybe?
jonathanpeppers added a commit to jonathanpeppers/maui that referenced this issue Feb 14, 2023
Context: dotnet#12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

Reviewing memory snapshots in the above apps, sometimes I would see
new `WeakEventManager+Subscription` objects be created and never go
away.

I noticed the `WeakEventManager.RemoveEventHandler()` method did not
remove any `Subscription` entries that it encountered were no longer
alive.

I could reproduce this problem in a test, and improved an existing
test to check this collection is cleared appropriately:

    readonly Dictionary<string, List<Subscription>> _eventHandlers = new();
rmarinho pushed a commit that referenced this issue Feb 15, 2023
…ns (#13333)

* [core] WeakEventManager.RemoveEventHandler() should clear subscriptions

Context: #12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

Reviewing memory snapshots in the above apps, sometimes I would see
new `WeakEventManager+Subscription` objects be created and never go
away.

I noticed the `WeakEventManager.RemoveEventHandler()` method did not
remove any `Subscription` entries that it encountered were no longer
alive.

I could reproduce this problem in a test, and improved an existing
test to check this collection is cleared appropriately:

    readonly Dictionary<string, List<Subscription>> _eventHandlers = new();

* Remove the `n - 1` business

This is closer to the standard `forr` snippet that has been around forever, just using `n` instead of `i`.
jonathanpeppers added a commit that referenced this issue Feb 17, 2023
Fixes: #12039
Fixes: #10560
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

In investigating various MAUI samples, I found the following object
leaking:

    WeakPropertyChangedProxy (referenced by ->)
        TypedBinding
        Binding

In ~2016, I contributed a fix to Xamarin.Forms:

xamarin/Xamarin.Forms@f6febd4

Back then, this solved the follow case:

1. You have a long-lived `ViewModel` class. Could be a singleton, etc.

2. Data-bind a `View` to this `ViewModel`.

3. The `ViewModel` indefinitely held on to any object that subscribed
   to `PropertyChanged`.

At the time, this solved a huge memory leak, because a data-bound
`View` would have a reference to its parent, then to its parent, etc.
Effectively this was leaking entire `Page`'s at the time.

Unfortunately, there was still a flaw in this change...
`WeakPropertyChangedProxy` hangs around forever instead! I could
reproduce this problem in unit tests, by accessing various internal
members through reflection -- asserting they were alive or not.

We do have another layer of indirection, where other objects are GC'd
that can free the `WeakPropertyChangedProxy`, such as:

    // Regular Binding
    ~BindingExpressionPart() => _listener?.Unsubscribe();
    // TypedBinding
    ~PropertyChangedProxy() => Listener?.Unsubscribe();

This means it would take two GC's for these objects to go away, but it
is better than the alternative -- they *can* actually go away now.

After testing apps with this change, sometimes I would get an
`InvalidOperationException` in `WeakReference<T>`:

https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs,103

So I added a parameter to `Unsubscribe(finalizer: true)`, to skip
`WeakReference<T>.SetTarget()` from finalizers.

After this change, I still found an issue! In my new unit test, the
following would hold onto a `ViemModel` object forever:

    VisualElement.BackgroundProperty.DefaultValue

This held the value of `Brush.Default`, in which
`Brush.Default.BindingContext` was the `ViewModel`!

My first thought was for `Brush.Default` to return `ImmutableBrush`:

    public static Brush Default => defaultBrush ??= new ImmutableBrush(null);

Because anyone could do `Brush.Default.Color = Colors.Red` if they liked.

When this didn't fix it, I found the underlying `_inheritedContext` is
what held a reference to my `ViewModel` object. I changed this value
to a `WeakReference`.

The types of leaks this fixes:

* Bindings to application-lifetime, singleton `ViewModel`s

* Scrolling `CollectionView`, `ListView`, etc. with data-bindings.

* Styles that were used on a `View` or `Page` that is now removed from
  the screen via navigation, de-parenting, etc.

Ok, I really think the leaks are gone now. Maybe?
Redth added a commit that referenced this issue Feb 18, 2023
* Added samples

* Fix the bug

* Added device tests

* Microsoft.Maui.ApplicationModel.Permissions: add Bluetooth permissions for Android (#12264)

* Android 12 has a new Bluetooth (runtime) permission scheme
* there are three different flavours; we request those that are present in the manifest

* Essentials: update public API (#12264)

* add Microsoft.Maui.ApplicationModel.Permissions.Bluetooth

* Remove obsoleted OpenGLView

* Restore accidentally deleted files

* Removed unnecessary loop

* Fix DotNetCoreTestSettings.Logger warning (#13068)

* added monochrome element to the AdaptiveIconDrawableXml (#12564)

To supporting user theming of app icons I've added the monochrome element to the AdaptiveIconDrawableXml

* Fix EvaluateJavaScriptAsync using Compatibility WebView Renderer (#12901)

* Fix Download warning (#13067)

* [create-pull-request] automated change (#13070)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Fix Html text rendering issue on Android

* Fix crash with a hidden CarouselView on iOS

* fix: Fixed nullable annotations for WeakEventManager. (#12950)

* Update CONTRIBUTING.md (#13093)

Removing references to handler PRs, since those have been done for ages.

* Remove Deprecated Application.Properties (#13089)

* Update dependencies from https://github.com/xamarin/xamarin-android build main-47a1df7b6911dc30b52164766984d3ed3c4f004e-1

Microsoft.Android.Sdk.Windows
 From Version 34.0.0-preview.1.147 -> To Version 34.0.0-preview.2.148

* [Windows] Fixes DatePicker format (#9924)

* Fixes Windows DatePicker format

* Fixes 'ddd' day format

* Fixes test

---------

Co-authored-by: Andrés Giudici <agiudici@tpssa.com.ar>

* Disable codeQL test

* Update WebAuthenticator to support custom ResponseDecoder (#11641) (#11710)

* (#11641) Added support for ResponseDecoder passed in the options.

* (#11641) Added CallbackUri as an optional property of the WebAuthenticatorResult

* (#11641) Added to Public API

* (#11641) Added IWebAuthenticatorResponseDecoder to public API

* (#11641) Added changes to WebAuthenticatorOptions to public API.

* (#11641) Split the ctor for WebAuthenticatorResult so there is no breaking change in public API.

* (#11641) Added public API definition for tizen

* Update src/Essentials/src/WebAuthenticator/WebAuthenticator.shared.cs

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/WebAuthenticator/WebAuthenticatorResult.shared.cs

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* (#11641) Moved docs into XML comments.

* (#11641) docs to XML comments

* (#11641) Removed XML docs for WebAuthenticator

* (#11641) Correct runfails for included xml fragments

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Remove PhoneDialer.Current (#13079)

* [listview] fixes for various null/empty DataTemplate

Fixes: #11203

The following breaks XAML Hot Reload:

1. Setup a working `ListView` and `DataTemplate`

2. Delete the `DataTemplate`'s body (as if I'm about to type a
   completely new view there).

3. Trigger a XAML Hot Reload. This can happen automatically if you
   just pause typing.

4. MAUI crashes at runtime:

    in Android.Views.ViewGroup.Layout at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net7.0/android-33/mcw/Android.Views.ViewGroup.cs:3369,5
    in Microsoft.Maui.Controls.Handlers.Compatibility.VisualElementRenderer<Microsoft.Maui.Controls.ListView>.OnLayout at D:\a\_work\1\s\src\Controls\src\Core\Compatibility\Handlers\Android\VisualElementRenderer.cs:54,6
    in Microsoft.Maui.Controls.Handlers.Compatibility.ListViewRenderer.OnLayout at D:\a\_work\1\s\src\Controls\src\Core\Compatibility\Handlers\ListView\Android\ListViewRenderer.cs:298,4

You can also create this problem in C#, like I did in a unit test:

    listView.ItemTemplate = new DataTemplate(() => /* valid template */);
    listView.ItemTemplate = new DataTemplate(); // broken
    listView.ItemTemplate = new DataTemplate(() => null); //broken

I could also get a slightly different crash:

    System.InvalidCastException: Specified cast is not valid.
    at Microsoft.Maui.Controls.Internals.TemplatedItemsList`2[[Microsoft.Maui.Controls.ItemsView`1[[Microsoft.Maui.Controls.Cell, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Controls.Cell, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].ActivateContent(Int32 index, Object item)

The "invalid cast" appears to be due to the changes in c57858f. It
returns a `new Label()` in some cases, which does not work with a
`ListView`. You need a `Cell` instead of `View` in that case.

The fixes appear to be in two places:

* `VisualElementRenderer.OnLayout`: use `is`, also simplifies the code

* `TemplatedItemsList.ActivateContent` : use `is` and call the default
  data template.

Now my tests pass, and I can't reproduce the issue in XAML Hot Reload
either!

* [iOS] Fix Entry Next Keyboard Button Finds Next TextField  (#11914)

* Enable the Next button on keyboard to find next text field - ios

* Use the most top superview or allow user to specify

* Add message for IQKeyboard and stop the upward search as the ContainerViewController

* add ThirdPartyNotice.txt from Android repo

* remove the ThirdPartyNotices.txt file for now

* address Shane comments and use more efficient search for next field

* make the search modular and more generic to fit inside ViewExtensions.cs

* change signatures for tests

* add third party notice

* Change names, support RightToLeft, loop back to beginning

* add comment for IsRtl

* Use logical tree ordering, add more unit tests, and create horizontalstacklayoutstub

---------

Co-authored-by: TJ Lambert <tjlambert@microsoft.com>

* Resolve some life cycle issues with `TabbedPage` when nested inside a `NavigationPage` (#11530)

* Fix fragment manager life cycle with TabbbedPage

* - add additional tests

* - add more tests and fix a couple more found issues

* - remove testing code

* - fix up tabbedpage gallery

* - fix up tests

* - fix up fragment management

* - cleanup

* - add additional tests

* - add delay

* Update StackNavigationManager.cs

* Update TabbedPageTests.cs

* Update ControlsHandlerTestBase.cs

* - remove disable nullable

* - add comment fix traversal

* - cleanup Destory checking code and add gallery tests

* - cleanup handling of adapter key

* - comment out ios

* - fix scenarios where navpage gets disconnected mid navigation

* Update MultiPageFragmentStateAdapter.cs

* Fix Modal page offset measuring for AdjustPan and AdjustResize (#12661)

* Watch for margin

* Fix modal margins and measuring when soft keyboard opens

* - fix offsets

* - force tests to setup testing scenario

* Update ModalNavigationManager.Android.cs

* - add additional comments

* Fix initial page and back button Navigation events (#12348)

* Fix initial page and back button Navigation events

* - add tests for backbutton

* - add comments and consolidate

* Update VisualElement.cs

* - validate pushed page fires navigated

* - fix tests

* - fix tests for reals

* Correctly propagate BindingContext in all ContentView scenarios (#12536)

* Correctly propagate BindingContext in all ContentView scenarios

* Apply suggestions from code review

Co-authored-by: MartyIX <203266+MartyIX@users.noreply.github.com>

* Updated samples

* Updated sample

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: MartyIX <203266+MartyIX@users.noreply.github.com>

* [iOS] Use same font size for Editor/Entry placeholders (#13140)

* [iOS] Use same font size for placeholder

* [iOS] Update placeholder fontsize when UITextView Font is updated

* Fix getting _defaultPlaceholderSize only 1 time

* [create-pull-request] automated change

* [iOS] Simplify the code used to set the same font size for Editor/Entry.

PR #13140 landed with a property
implementation that is more complicatd than needed (also a little
unsafe).

Changes in this PR:

1. Use a nullable nfloat to ensure that we do not use a magic number as
   the default value of the variable.
2. Simplify the if nests. There is no needed to have that many nested
   code to achiecve the same. This implementation does the same with a
   much simpler approach.

* Use `is not`, save a few lines of code

* Update src/Core/src/Platform/iOS/MauiTextView.cs

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Update src/Core/src/Platform/iOS/MauiTextView.cs

* Even simpler.

* Bump Xamarin.Firebase.AppIndexing from 120.0.0.10 to 120.0.0.11

Bumps [Xamarin.Firebase.AppIndexing](https://github.com/xamarin/GooglePlayServicesComponents) from 120.0.0.10 to 120.0.0.11.
- [Release notes](https://github.com/xamarin/GooglePlayServicesComponents/releases)
- [Commits](https://github.com/xamarin/GooglePlayServicesComponents/commits)

---
updated-dependencies:
- dependency-name: Xamarin.Firebase.AppIndexing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Make MAUI into 1 workload and lots of NuGets instead of a full workload (#11206)

### Description

This change moves most - if not all - the logic, assemblies, build tasks, targets and props into NuGet packages. This allows .NET MAUI to be usable without having to care about what version of the workload is installed.

There are still a few things - mostly the automagic and Windows fixes - in the workload pack, but this is probably temporary and/or non-essential for the working of the build. Things like the project capabilities are still in the workload as this is needed for the IDE and cannot be in NuGet packages.

Everything else is now inside a NuGet package that can be upgraded, pinned and otherwise used without requiring VS to have installed the workload to match. There is the benefit of the NuGet packages being installed on disk and thus reducing/removing the need to download. But that is minimal now since we have smaller and fewer packages.

* Bump Xamarin.GooglePlayServices.Maps from 118.1.0 to 118.1.0.1

Bumps [Xamarin.GooglePlayServices.Maps](https://github.com/xamarin/GooglePlayServicesComponents) from 118.1.0 to 118.1.0.1.
- [Release notes](https://github.com/xamarin/GooglePlayServicesComponents/releases)
- [Commits](https://github.com/xamarin/GooglePlayServicesComponents/commits)

---
updated-dependencies:
- dependency-name: Xamarin.GooglePlayServices.Maps
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add the new dll to the sign list (#13168)

* [iOS] Fix issue using SVG in SwipeItem Icon (#12882)

* Set the SwipeItem Icon with the correct size after load the SwipeItem (Frame is not empty)

* Added comments

* Make SwipeItemButton public and add to public api

---------

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Remove Navigation workaround (#13170)

* Add some capabilities! (#13171)

* Fix the WorkloadManifest.json (#13172)

* [create-pull-request] automated change

* Fix a couple life cycle scenarios on shell modals (#13177)

* Fix a couple life cycle scenarios on shell modals

* - cleanup code

* Don't auto-close s/move-to-vs-feedback issues (#13209)

After discussion with the VS tooling folks, we decided it can be harmful to auto-close these issues because we can end up losing issues entirely if they never get moved to VS feedback and/or Azure DevOps.

We'll look into how to automate these issues, but for now we want to stop losing data.

* Close open cursors correctly (#13202)

* [Windows] Add convenience and nullable safe method. (#13205)

During the code reviews I have noticed several occurrences of the of the
following pattern:

```csharp
if (nativeSlider.GetFirstDescendant<Thumb>() is Thumb thumb)
{
  thumb.Height = defaultThumbSize.Value.Height;
  thumb.Width = defaultThumbSize.Value.Width;
}
```

The above works, but it is abussing the is operator and is making us
type more than is really needed (several ocurrences of the type). The
given method will be used as follows:

```csharp
if (nativeSlider.TryGetFirstDescendant<Thumb>(out var thumb))
{
  thumb.Height = defaultThumbSize.Value.Height;
  thumb.Width = defaultThumbSize.Value.Width;
}
```
or
```csharp
if (nativeSlider.TryGetFirstDescendant(out Thumb? thumb))
{
  thumb.Height = defaultThumbSize.Value.Height;
  thumb.Width = defaultThumbSize.Value.Width;
}
```
Nullability is not needed thansk to the NotNullWhenAttribute.

* Fix back button tap for older iOS APIs (#13204)

* Fix back button tap for older iOS APIs

* - fix ios14

* Add NotNullWhen to IsAlive() (#13214)

* Add more tests for Graphics (#13208)

* Wire up WebView2 to window life cycle (#13206) Fixes #10436 Fixes #8323 Fixes #7317 Fixes #12956

* [Android] Fix crash setting SelectedTabColor on TabbedPage (#12924) Fixes #12904

* Fix crash setting SelectedTabColor on Android TabbedPage

* Update src/Controls/src/Core/Platform/Android/TabbedPageManager.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Refactoring code

* Small refactoring and included comments

* Changes based on feedback

---------

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* [create-pull-request] automated change (#13217)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update dependencies from https://github.com/xamarin/xamarin-android build main-a9313d52448f931709844a7faf71b2761b0158c9-1 (#13199)

Microsoft.Android.Sdk.Windows
 From Version 34.0.0-preview.2.148 -> To Version 34.0.0-preview.2.149

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* [main] Update dependencies from xamarin/xamarin-macios (#13195)

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.7

Microsoft.iOS.Sdk
 From Version 16.2.1024 -> To Version 16.2.1025

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.7

Microsoft.tvOS.Sdk
 From Version 16.1.1521 -> To Version 16.1.1522

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.7

Microsoft.macOS.Sdk
 From Version 13.1.1024 -> To Version 13.1.1025

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.7

Microsoft.MacCatalyst.Sdk
 From Version 16.2.1024 -> To Version 16.2.1025

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.12

Microsoft.iOS.Sdk
 From Version 16.2.1024 -> To Version 16.2.1026

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.12

Microsoft.tvOS.Sdk
 From Version 16.1.1521 -> To Version 16.1.1523

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.12

Microsoft.macOS.Sdk
 From Version 13.1.1024 -> To Version 13.1.1026

* Update dependencies from https://github.com/xamarin/xamarin-macios build 20230208.12

Microsoft.MacCatalyst.Sdk
 From Version 16.2.1024 -> To Version 16.2.1026

---------

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* [iOS] Better Find Next Textfield Algo (#13174)

* Use the better algorithm

* prepare for nulls and index less

---------

Co-authored-by: TJ Lambert <tjlambert@microsoft.com>

* [Android] Align dash effect between Border and Shapes (#12693)

* Align dash effect between Border and Shapes on Android

* Update src/Core/src/Graphics/MauiDrawable.Android.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

---------

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* [Android] Avoid to update Shell Toolbar colors if already disposed the Tracker (#12539)

* Avoid to update Shell Toolbar colors if already disposed the Tracker

* Changes from PR feedback

* Update src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarAppearanceTracker.cs

Co-authored-by: Shane Neuville <shneuvil@microsoft.com>

---------

Co-authored-by: Shane Neuville <shneuvil@microsoft.com>

* Fix wrong conversions between Graphics RectF and Android RectF (#13225)

* [build] use stable bits in main (#13201)

Context: #11805
Fixes: #12762

There are various NuGet feed issues caused by using nightly builds of
.NET SDK and workloads. #11805 also appears to be blocked by an
unknown problem -- meaning we are using older bits in `main`
currently.

To use stable bits:

* Hardcode the latest stable version numbers of everything.

* Pass `--version 7.0.101` to the `dotnet-install` script.

* Work around the weird, unknown build errors?

Other changes:

* Pass `--skip-sign-check` so that the `tizen` workload can be
  installed with a signed .NET SDK. We already do this on various
  release branches like `release/8.0.1xx-preview1`.

* Build `Microsoft.Maui-mac.slnf` in parallel, this apparently works
  around the unknown issue in #11805?

* Remove `$(DotNetFeedUrl)`, as it breaks the `dotnet-install` script
  on macOS. This URL changes from time to time.

* Build for a single maccatalyst RID in some projects. This attributed
  to other build errors once `Microsoft.Maui-mac.slnf` built in parallel.

Tracking this in: xamarin/xamarin-macios#17497

* Don't refresh the filtered tests if the filter hasn't actually changed (#13236)

* [CI] Install the android and iOS dotnet version when they are diff to the maui one. (#13228)

* [CI] Install the android and iOS dotnet version when they are diff to the maui one.

This extra conditional command execution allows to install the donet
versions needed by the android and iOS runtimes. This will allow us to
be able to work around a situation in which there is a mismatch between
the SDKs.

* Get the versions from the sdk props.

* Fix pwsh install, use MicrosoftNETCoreAppRefPackageVersion

---------

Co-authored-by: Peter Collins <pecolli@microsoft.com>

* fix shadow visibility on Windows (#10996)

* [create-pull-request] automated change (#13237)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [Android] Fix shadows size in clipped views (#11603) Fixes #11578

* Fix shadows clipping views

* Fix build errors

* Capture and cache Context usage

We've found Context can be a bit expensive to get in a large frequency of calls (#8001), so we can avoid this by capturing and caching the instance.

* Removed duplicated test

* Revert latest changes

---------

Co-authored-by: redth <jondick@gmail.com>
Co-authored-by: Rachel Kang <rachelkang@microsoft.com>

* [iOS/Catalyst] Fix Shell TitleView rendering issues on iOS 16  (#12834) Fixes #10128 Fixes #11309

* Fix the issue

* Added a sample in the Gallery

* Added Device Test

* Fix test

* Update src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

---------

Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Remove TargetIdiom (#13090)

* Remove TargetIdiom

* Update Device.cs

* Fix unshipped txt files

---------

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* [core] `WeakEventManager+Subscription` needs `IEquatable` (#13232)

Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: #12039

Using the Visual Studio's `.NET Object Allocation Tracking` profiler
on the sample above I noticed after app launch:

    Microsoft.Maui.WeakEventManager+Subscription
    Allocations: 686,114
    Bytes: 21,955,648

After spitting out my coffee, I drilled in a bit to see where these
are being created:

    System.Collections.Generic.ObjectEqualityComparer<Microsoft.Maui.WeakEventManager+Subscription>.IndexOf

It turns out this `struct` doesn't implement `IEquatable<T>`:

https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1815

To solve this:

* `Subscription` is private, so we can make it a `readonly struct`.

* `dotnet_diagnostic.CA1815.severity = error` across the entire repo.

* Implement `IEquatable<T>` for all `struct` types.

After these changes, I can't find `Microsoft.Maui.WeakEventManager+Subscription`
in the memory report at all. Which assuming means, I saved ~21 MB of
allocations in this app.

Note that this doesn't actually solve #12039, as I'm still
investigating the leak. Maybe this partially closes the floodgate?

* Fix `struct`s in Controls.Core

Note that I did not update these, as they are some "internal" parts
from Xamarin.Forms:

* `Profile`
* `Datum`

We might actually just consider removing these in the future.

* Suppress warnings in Compatibility

I assume these structs aren't nearly as important, so ignoring a few.

They appear to be called once at startup in most cases.

* Disable `CA1815` in tests.

* feat: Added nullable annotations for IValueConverter. (#13173)

* feat: Added nullable annotations for IValueConverter.

* feat: Added nullable annotations for IValueConverter.

* Remove Compatibility packages by default (#13165)

* Remove Compatibility packages by default

* we need thisin our sample

* [Windows] Fix issue with caching the page that holds unfocused control (#13028)

* [Windows] Fix issue with caching the page that holds unfocused control

* Simplify condition

* [test] Use AutoResetEvent for entry focus test

* Use tabStop to unfocus

* [Housekeeping] Revert changes from 11721 (#13253)

* Revert changes from 11721

* Revert device tests

* Update Essentials SMS API Docs (#12849)

* Add Essentials SMS API Docs

* Update Sms.shared.cs

* Update src/Essentials/src/Sms/Sms.shared.cs

Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>

---------

Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>

* Let the Grid skip * measurements during the first pass if they'll be overwritten later (#13255)

* [CI] Allow to find the eng folder when multiple projects are checkedout. (#13254)

One of the curious decisions from the VSTS team was to use a different
directory for the checkout depending if the project was checkoued alone
or was checkedout along with other repos.

If we only check out maui, the directory will be the
$(DefaultWorkingDirectory), but if are checkingout other repos, the
directory will be $(DefaultWorkingDirectory)/maui".

In order to be able to use the provisioning scripts from other pipeline
along other projects (megapipeline) we must adapt our templates to that
diff directory structure.

* [create-pull-request] automated change

* [CI] Allow to pass the checkout dir to the packs template. (#13264)

* Update dotnet-autoformat-pr.yml (#13296)

* [housekeeping] Update dotnet-autoformat-pr.yml (#13300)

* Update dotnet-autoformat-pr.yml

* Fix github comment

* [Windows] Correctly set the Slider ThumbImageSource (#13194)

* Correctly set the Windows Slider ThumbImageSource

* Update src/Core/src/Handlers/Slider/SliderHandler.Windows.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Update src/Core/tests/DeviceTests/Handlers/Slider/SliderHandlerTests.Windows.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Updated sample

* Refactoring code

* Refactoring code

---------

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* When measuring FlexLayout unconstrained, allow child to be desired size (#13216)

* When measuring FlexLayout unconstrained, allow child to be desired size (rather than zero)
Fixes #11909

* Fix issue on Windows with HorizontalStackLayout

* De-duplicate some test code

* [Essentials] Geolocation foreground listening (#9572)

* added geolocation foreground listening public API without implementation

* added section on geolocation sample page for foreground listening feature

* implemented geolocation foreground listening for Android, iOS, MacOS and UWP

* moved common code for determining DesiredAccuracy on UWP to extension method

* renamed class ListeningRequest to GeolocationListeningRequest

* renamed property IsListening to IsListeningForeground

* added xml documentation for all new public methods and properties

* implemented event LocationError, using enum GeolocationError and class GeolocationErrorEventArgs

* fixed potential leak where ContinuousLocationListener keeps the reference to the GeolocationImplementation on iOS

* changed StopListeningForegroundAsync() to StopListeningForeground() and return void

* fixed error in Essentials samples where async keyword is not necessary anymore

* enabled nullable checks for GeolocationListeningRequest class

* renamed ListeningRequest.ios.macos.cs to match class name; no source code changes

* call StopListeningForeground() on Android, iOS and macOS before signalling LocationError event, to make behavior consistent with Windows

* replaced throwing ArgumentNullException with ArgumentNullException.ThrowIfNull()

* added xml documentation for all newly added public geolocaion foreground listening APIs

* removed duplicated code for determining GeolocationAccuracy on iOS and macOS

* renamed event LocationError to ListeningFailed and GeolocationErrorEventArgs to GeolocationListeningFailedEventArgs

* fixed IsListeningForeground property on Windows

* Fixed naming

---------

Co-authored-by: Gerald Versluis <gerald.versluis@microsoft.com>

* [controls] fix memory leak in Style and AttachedCollection (#13260)

Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak
Context: #12039

Using the Visual Studio's `.NET Object Allocation Tracking` profiler
on the sample above I noticed after using the app and taking snapshots:

Snapshot 2:

    WeakReference<Microsoft.Maui.Controls.BindableObject>
    Count: 1,545
    Bytes: 37,080

Snapshot 10:

    WeakReference<Microsoft.Maui.Controls.BindableObject>
    Count: 1,657
    Bytes: 39,768

It appears memory usage is slowly growing by about ~2.45KB each time I
navigate forward a page then return.

f8171b4 introduced a `CleanupTrigger`, but the code has a slight issue:

    void CleanUpWeakReferences()
    {
        if (_targets.Count < _cleanupThreshold)
        {
            return;
        }

        _targets.RemoveAll(t => !t.TryGetTarget(out _));
        _cleanupThreshold = _targets.Count + CleanupTrigger;
    }

Because `_cleanupThreshold` is modified at the bottom of this method,
the `_targets` collection increases by 128 in size over time. The
result being lots of tiny `WeakReference<T>` objects in memory, but
not the actual underlying `T` target.

I did a little research to try to find a better collection than
`List<WeakReference<T>>`:

* https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.conditionalweaktable-2
* https://source.dot.net/#Microsoft.Extensions.Caching.Memory/MemoryCache.cs
* https://source.dot.net/#PresentationFramework/System/Windows/Input/KeyboardNavigation.cs,08271c29723aa10a

I did not find one that exactly met our needs, so I wrote a very
simple `WeakList<T>`. It cleans up `WeakReference<T>` that are no
longer alive after N operations. I set this threshold to 32 to start,
we can modify this later if needed. This makes the above samples call
it a couple times for large `CollectionView`'s, which seems reasonable.

After these changes, I'm able to navigate in the app over and over
with stable memory usage:

| ID | Objects | Heap Size     |
| -- | --:     | --:           |
| 1  | 107,885 | 407,645.87 KB |
| 2  |   2,267 | 401,126.22 KB |

This was after navigating through the app *many* times, and it
actually went *down*.

Then I found `Microsoft.Maui.Internals.WeakList<T>`, which I did not
like quite as much as my implementation. I deleted/replaced its usage
adding new unit tests for `WeakList<T>`.

Note that I believe I found one other leak, so this doesn't fully
solve #12039 yet.

* [create-pull-request] automated change (#13306)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [controls] one less WeakReference in TypedBinding (#13304)

Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: #12039

When reviewing the memory snapshots in #12039, I noticed a
`WeakReference<T>` that could be completely removed in `TypedBinding`.
`BindingExpression.WeakPropertyChangedProxy` already had this exposed
as a `Source` property we can just use instead.

I also updated some `TypedBindingUnitTests` to assert more things are
GC'd properly.

I don't think this fixes an issue, except saving ~8 bytes per
`TypedBinding` and makes memory snapshots smaller/easier to read.

* Update Essentials API Docs Misc (#12996)

* Update Essentials API Docs Misc

* Some more

* Placemark

* PlacemarkExtensions

* SensorSpeed

* UnitConverters

* Delete UnitConverters.xml

* Apple Sign In

* WebAuthenticator

* Some more

* Update src/Essentials/src/FileSystem/FileSystem.shared.cs

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Apply suggestions from code review

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* Obsolete some of the AutomationProperties (#13104)

* Obsolete some of the AutomationProperties

* Update SemanticProperties.cs

* [Resizetizer] Do not update images if they have not been updated. (#13224)

* [Resizetizer] Do not update images if they have not been updated.

Rather than generating the images on every build we should
check to see if the source has changed before calling the
expensive generation processes. This seems to take about 150-200ms
off an incremental build when only one image file was changed.

* Added Unit Tests. Added support for iOS and Windows

* Updated based on feedback

* Rework

* Rework

* Thank you for your pull request. We are auto-formating your source code to follow our code guidelines.

---------

Co-authored-by: GitHub Actions Autoformatter <autoformat@example.com>

* [Windows] Fix crash on Windows WebView updating the Html Source more than once (#13222)

* Fix crash on Windows WebView updating the Html Source more than once

* Fixed build error

* Update src/Core/src/Platform/Windows/WebViewExtensions.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

---------

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Update dependencies from https://github.com/xamarin/xamarin-android build main-7c42c60d587ad4544a5ee326adfa8b1d23f72204-1 (#13316)

Microsoft.Android.Sdk.Windows
 From Version 34.0.0-preview.2.149 -> To Version 34.0.0-preview.2.151

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* [core] WeakEventManager.RemoveEventHandler() should clear subscriptions (#13333)

* [core] WeakEventManager.RemoveEventHandler() should clear subscriptions

Context: #12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

Reviewing memory snapshots in the above apps, sometimes I would see
new `WeakEventManager+Subscription` objects be created and never go
away.

I noticed the `WeakEventManager.RemoveEventHandler()` method did not
remove any `Subscription` entries that it encountered were no longer
alive.

I could reproduce this problem in a test, and improved an existing
test to check this collection is cleared appropriately:

    readonly Dictionary<string, List<Subscription>> _eventHandlers = new();

* Remove the `n - 1` business

This is closer to the standard `forr` snippet that has been around forever, just using `n` instead of `i`.

* reduce duplicate IndexOf calls (#12599)

* Auto-format source code

* [create-pull-request] automated change (#13337)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [main] Update dependencies from dotnet/xharness (#11867)

* Update dependencies from https://github.com/dotnet/xharness build 20221128.1

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.22578.1

* Update default dotner version installed

* Update dependencies from https://github.com/dotnet/xharness build 20221207.1

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.22607.1

* Update versions to try again

* MicrosoftDotnetSdkInternalPackageVersion

* Try stable feed

* Extensions version back

* Don t bump version

* Update dependencies from https://github.com/dotnet/xharness build 20221215.1

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.22615.1

* Update dependencies from https://github.com/dotnet/xharness build 20221220.1

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.22620.1

* Update dependencies from https://github.com/dotnet/xharness build 20230102.2

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.23052.2

* Update dependencies from https://github.com/dotnet/xharness build 20230109.1

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.23059.1

* Update dependencies from https://github.com/dotnet/xharness build 20230118.2

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.23068.2

* Update dependencies from https://github.com/dotnet/xharness build 20230123.2

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.23073.2

* Update dependencies from https://github.com/dotnet/xharness build 20230202.1

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.23102.1

* Update dependencies from https://github.com/dotnet/xharness build 20230210.1

Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit
 From Version 1.0.0-prerelease.22569.1 -> To Version 1.0.0-prerelease.23110.1

---------

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: Matthew Leibowitz <mattleibow@live.com>

* ItemContentControl - apply bindings once for ItemTemplate (Windows) (#10999)

* avoid setting bindings twice

* add sample code for testing purposes

* [Android] Don't lose the padding when background is set (#13301) fixes #12224

* [Android] Don't lose the padding when background is set

* Auto-format source code

---------

Co-authored-by: GitHub Actions Autoformatter <autoformat@example.com>

* Fix setting bottom tab icon title (#12889) Fixes #12105

* Don't reset entire menu when icon/title changes

* Auto-format source code

---------

Co-authored-by: GitHub Actions Autoformatter <autoformat@example.com>

* Fix install .net

* [macOS] Fix crash using Shell SearchHandler on Catalyst (#11926)

* Fix crash using Shell SearchHandler on Catalyst

* Updated changes

* Added device test

* Update src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/UIContainerCell.cs

Co-authored-by: Shane Neuville <shneuvil@microsoft.com>

* Fix merge issue

* Moved test

---------

Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>

* Finalize Essentials API Docs (#13320)

* Final docs + WarningsAsErrors on Missing Docs

* Delete all unused XML files

* Update Permissions.tizen.cs

* [iOS] Fix sizing of button when using CharacterSpacing (#13250) Fixes #10293

* [iOS] Set the attributed title on the button and not the inner label

* Just small cleanup on this file

* Reinstate test fix

---------

Co-authored-by: E.Z. Hart <hartez@gmail.com>

* fix(ShellView): Fixed an issue in `ShellView` where items added via code would be duplicated (#13326)

Co-authored-by: Mike Corsaro <mikecorsaro@microsoft.com>

* Changes in project template to avoid BoxView mistake (#13348)

* Bump coverlet.collector from 3.1.2 to 3.2.0 (#13359)

Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 3.1.2 to 3.2.0.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/commits/v3.2.0)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump Microsoft.AspNetCore.Authorization from 7.0.2 to 7.0.3 (#13350)

* Bump Microsoft.AspNetCore.Authorization from 7.0.2 to 7.0.3

Bumps [Microsoft.AspNetCore.Authorization](https://github.com/dotnet/aspnetcore) from 7.0.2 to 7.0.3.
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](dotnet/aspnetcore@v7.0.2...v7.0.3)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authorization
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Move other packages for 7.0.3

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Update dependencies from https://github.com/xamarin/xamarin-android build main-aa54ed3d57d7c54095b869c1c0c3a7d7e4761d85-1 (#13360)

Microsoft.Android.Sdk.Windows
 From Version 34.0.0-preview.2.151 -> To Version 34.0.0-preview.2.152

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* [Windows] Fix crash using complex html content (#11409)

* Fix crash using complex html content on Windows

* Use device test in all the platforms

* [CI] Enure the pwsh is in the right dir. (#13370)

Follow up of #13264

We need to be sure that the pwsh is executed from the right dir, the
simplest way is to set the working dir for the step.

* [create-pull-request] automated change (#13373)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Added pending changes in Android AlertManager (#11989)

* Update dotnet-autoformat-pr-push.yml (#13390)

* Ensure OnMeasure always calls SetMeasuredDimension in ShellPageContainer (#13153) Fixes #13152

* At a minimum, call the base method

* Copy pattern from elsewhere in MAUI

* Implement requested changes

* Clarify test (#13363)

* Clarify test

* - fix spelling

* Bump Microsoft.Web.WebView2 from 1.0.1518.46 to 1.0.1587.40 (#13389)

Bumps Microsoft.Web.WebView2 from 1.0.1518.46 to 1.0.1587.40.

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* [Android] Fix crash adding items to CollectionView on navigating (#13385) Fixes #12219

* Fix crash adding items to CollectionView on Android navigating

* Changes in test

* [iOS/MacCatalyst] Fix Editor scrolling (#13234)

* [iOS] Don't update the offset if there's no space available

* [iOS] Use the MauiLabel to set a label with insets

Using the constrains was keeping the UITextView from scrolling

* [Windows] Fix Shell FlyoutBackground property (#13132)

* Fix issue using Shell FlyoutBackground on Windows

* Changes based on PR feedback

* Changes based on PR feedback

* Updated test

* Update src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.Windows.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Add missing ;

---------

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* [core] fix memory leaks in bindings (#13327)

Fixes: #12039
Fixes: #10560
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

In investigating various MAUI samples, I found the following object
leaking:

    WeakPropertyChangedProxy (referenced by ->)
        TypedBinding
        Binding

In ~2016, I contributed a fix to Xamarin.Forms:

xamarin/Xamarin.Forms@f6febd4

Back then, this solved the follow case:

1. You have a long-lived `ViewModel` class. Could be a singleton, etc.

2. Data-bind a `View` to this `ViewModel`.

3. The `ViewModel` indefinitely held on to any object that subscribed
   to `PropertyChanged`.

At the time, this solved a huge memory leak, because a data-bound
`View` would have a reference to its parent, then to its parent, etc.
Effectively this was leaking entire `Page`'s at the time.

Unfortunately, there was still a flaw in this change...
`WeakPropertyChangedProxy` hangs around forever instead! I could
reproduce this problem in unit tests, by accessing various internal
members through reflection -- asserting they were alive or not.

We do have another layer of indirection, where other objects are GC'd
that can free the `WeakPropertyChangedProxy`, such as:

    // Regular Binding
    ~BindingExpressionPart() => _listener?.Unsubscribe();
    // TypedBinding
    ~PropertyChangedProxy() => Listener?.Unsubscribe();

This means it would take two GC's for these objects to go away, but it
is better than the alternative -- they *can* actually go away now.

After testing apps with this change, sometimes I would get an
`InvalidOperationException` in `WeakReference<T>`:

https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs,103

So I added a parameter to `Unsubscribe(finalizer: true)`, to skip
`WeakReference<T>.SetTarget()` from finalizers.

After this change, I still found an issue! In my new unit test, the
following would hold onto a `ViemModel` object forever:

    VisualElement.BackgroundProperty.DefaultValue

This held the value of `Brush.Default`, in which
`Brush.Default.BindingContext` was the `ViewModel`!

My first thought was for `Brush.Default` to return `ImmutableBrush`:

    public static Brush Default => defaultBrush ??= new ImmutableBrush(null);

Because anyone could do `Brush.Default.Color = Colors.Red` if they liked.

When this didn't fix it, I found the underlying `_inheritedContext` is
what held a reference to my `ViewModel` object. I changed this value
to a `WeakReference`.

The types of leaks this fixes:

* Bindings to application-lifetime, singleton `ViewModel`s

* Scrolling `CollectionView`, `ListView`, etc. with data-bindings.

* Styles that were used on a `View` or `Page` that is now removed from
  the screen via navigation, de-parenting, etc.

Ok, I really think the leaks are gone now. Maybe?

* [CI] Fix more paths in the packs.yml to work with the unified pipeline.

* [CI] Fix the step to copy the metadata.

* Auto-format source code

* Add implicit package reference for Compat (#13427)

Ultimately we want this to be an implicit reference which is not included by default and opt-in, however visual studio's Live Visual tree currently depends on the assembly existing and being loaded so we cannot yet remove it.

The default property assignment can be removed once VS is ready for this.

* Add shell pages via controller instead of handler (#13332)

* Add shell pages via controller instead of handler

* Auto-format source code

* - cleanup

* - add wait

* - push test into modal to isolate better

---------

Co-authored-by: GitHub Actions Autoformatter <autoformat@example.com>

* Use and clear a local nuget cache (#13256)

* Use and clear a local nuget cache

* more

* Have Frame use MinimumHeight/Width for minimums instead of constraints (#13336)

* Have Frame use MinimumHeight/Width for minimums instead of constraints
Fixes #13074

* Auto-format source code

* Adjust test for other screen sizes/densities

* Update src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Make legacy min Frame size a constant

* Auto-format source code

* Make Frame test less awkward

* Auto-format source code

---------

Co-authored-by: GitHub Actions Autoformatter <autoformat@example.com>
Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Javier Suárez <javiersuarezruiz@hotmail.com>
Co-authored-by: Janus Weil <janus@gcc.gnu.org>
Co-authored-by: Gerald Versluis <gerald.versluis@microsoft.com>
Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: Lutz Roeder <lutzroeder@users.noreply.github.com>
Co-authored-by: Fabian <f.becker33@outlook.de>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Konstantin S <havendv@gmail.com>
Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Andrés Giudici <agiudici@gmail.com>
Co-authored-by: Andrés Giudici <agiudici@tpssa.com.ar>
Co-authored-by: Adrian Hall <photoadrian@outlook.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
Co-authored-by: TJ Lambert <50846373+tj-devel709@users.noreply.github.com>
Co-authored-by: TJ Lambert <tjlambert@microsoft.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
Co-authored-by: MartyIX <203266+MartyIX@users.noreply.github.com>
Co-authored-by: Manuel de la Pena <mandel@microsoft.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Eilon Lipton <Eilon@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Peter Collins <pecolli@microsoft.com>
Co-authored-by: Espen Røvik Larsen <espenrl@users.noreply.github.com>
Co-authored-by: Rachel Kang <rachelkang@microsoft.com>
Co-authored-by: vividos <michael.fink@asamnet.de>
Co-authored-by: Dean Ellis <dellis1972@googlemail.com>
Co-authored-by: GitHub Actions Autoformatter <autoformat@example.com>
Co-authored-by: Trivalik <3148279+trivalik@users.noreply.github.com>
Co-authored-by: E.Z. Hart <hartez@gmail.com>
Co-authored-by: Mike Corsaro <corsarom@gmail.com>
Co-authored-by: Mike Corsaro <mikecorsaro@microsoft.com>
Co-authored-by: Nicholas Bauer <nicholasbauer@outlook.com>
tj-devel709 pushed a commit to tj-devel709/maui that referenced this issue Feb 21, 2023
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: dotnet#12039

Using the Visual Studio's `.NET Object Allocation Tracking` profiler
on the sample above I noticed after app launch:

    Microsoft.Maui.WeakEventManager+Subscription
    Allocations: 686,114
    Bytes: 21,955,648

After spitting out my coffee, I drilled in a bit to see where these
are being created:

    System.Collections.Generic.ObjectEqualityComparer<Microsoft.Maui.WeakEventManager+Subscription>.IndexOf

It turns out this `struct` doesn't implement `IEquatable<T>`:

https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1815

To solve this:

* `Subscription` is private, so we can make it a `readonly struct`.

* `dotnet_diagnostic.CA1815.severity = error` across the entire repo.

* Implement `IEquatable<T>` for all `struct` types.

After these changes, I can't find `Microsoft.Maui.WeakEventManager+Subscription`
in the memory report at all. Which assuming means, I saved ~21 MB of
allocations in this app.

Note that this doesn't actually solve dotnet#12039, as I'm still
investigating the leak. Maybe this partially closes the floodgate?

* Fix `struct`s in Controls.Core

Note that I did not update these, as they are some "internal" parts
from Xamarin.Forms:

* `Profile`
* `Datum`

We might actually just consider removing these in the future.

* Suppress warnings in Compatibility

I assume these structs aren't nearly as important, so ignoring a few.

They appear to be called once at startup in most cases.

* Disable `CA1815` in tests.
tj-devel709 pushed a commit to tj-devel709/maui that referenced this issue Feb 21, 2023
)

Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak
Context: dotnet#12039

Using the Visual Studio's `.NET Object Allocation Tracking` profiler
on the sample above I noticed after using the app and taking snapshots:

Snapshot 2:

    WeakReference<Microsoft.Maui.Controls.BindableObject>
    Count: 1,545
    Bytes: 37,080

Snapshot 10:

    WeakReference<Microsoft.Maui.Controls.BindableObject>
    Count: 1,657
    Bytes: 39,768

It appears memory usage is slowly growing by about ~2.45KB each time I
navigate forward a page then return.

f8171b4 introduced a `CleanupTrigger`, but the code has a slight issue:

    void CleanUpWeakReferences()
    {
        if (_targets.Count < _cleanupThreshold)
        {
            return;
        }

        _targets.RemoveAll(t => !t.TryGetTarget(out _));
        _cleanupThreshold = _targets.Count + CleanupTrigger;
    }

Because `_cleanupThreshold` is modified at the bottom of this method,
the `_targets` collection increases by 128 in size over time. The
result being lots of tiny `WeakReference<T>` objects in memory, but
not the actual underlying `T` target.

I did a little research to try to find a better collection than
`List<WeakReference<T>>`:

* https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.conditionalweaktable-2
* https://source.dot.net/#Microsoft.Extensions.Caching.Memory/MemoryCache.cs
* https://source.dot.net/#PresentationFramework/System/Windows/Input/KeyboardNavigation.cs,08271c29723aa10a

I did not find one that exactly met our needs, so I wrote a very
simple `WeakList<T>`. It cleans up `WeakReference<T>` that are no
longer alive after N operations. I set this threshold to 32 to start,
we can modify this later if needed. This makes the above samples call
it a couple times for large `CollectionView`'s, which seems reasonable.

After these changes, I'm able to navigate in the app over and over
with stable memory usage:

| ID | Objects | Heap Size     |
| -- | --:     | --:           |
| 1  | 107,885 | 407,645.87 KB |
| 2  |   2,267 | 401,126.22 KB |

This was after navigating through the app *many* times, and it
actually went *down*.

Then I found `Microsoft.Maui.Internals.WeakList<T>`, which I did not
like quite as much as my implementation. I deleted/replaced its usage
adding new unit tests for `WeakList<T>`.

Note that I believe I found one other leak, so this doesn't fully
solve dotnet#12039 yet.
tj-devel709 pushed a commit to tj-devel709/maui that referenced this issue Feb 21, 2023
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: dotnet#12039

When reviewing the memory snapshots in dotnet#12039, I noticed a
`WeakReference<T>` that could be completely removed in `TypedBinding`.
`BindingExpression.WeakPropertyChangedProxy` already had this exposed
as a `Source` property we can just use instead.

I also updated some `TypedBindingUnitTests` to assert more things are
GC'd properly.

I don't think this fixes an issue, except saving ~8 bytes per
`TypedBinding` and makes memory snapshots smaller/easier to read.
tj-devel709 pushed a commit to tj-devel709/maui that referenced this issue Feb 21, 2023
…ns (dotnet#13333)

* [core] WeakEventManager.RemoveEventHandler() should clear subscriptions

Context: dotnet#12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

Reviewing memory snapshots in the above apps, sometimes I would see
new `WeakEventManager+Subscription` objects be created and never go
away.

I noticed the `WeakEventManager.RemoveEventHandler()` method did not
remove any `Subscription` entries that it encountered were no longer
alive.

I could reproduce this problem in a test, and improved an existing
test to check this collection is cleared appropriately:

    readonly Dictionary<string, List<Subscription>> _eventHandlers = new();

* Remove the `n - 1` business

This is closer to the standard `forr` snippet that has been around forever, just using `n` instead of `i`.
tj-devel709 pushed a commit to tj-devel709/maui that referenced this issue Feb 21, 2023
Fixes: dotnet#12039
Fixes: dotnet#10560
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

In investigating various MAUI samples, I found the following object
leaking:

    WeakPropertyChangedProxy (referenced by ->)
        TypedBinding
        Binding

In ~2016, I contributed a fix to Xamarin.Forms:

xamarin/Xamarin.Forms@f6febd4

Back then, this solved the follow case:

1. You have a long-lived `ViewModel` class. Could be a singleton, etc.

2. Data-bind a `View` to this `ViewModel`.

3. The `ViewModel` indefinitely held on to any object that subscribed
   to `PropertyChanged`.

At the time, this solved a huge memory leak, because a data-bound
`View` would have a reference to its parent, then to its parent, etc.
Effectively this was leaking entire `Page`'s at the time.

Unfortunately, there was still a flaw in this change...
`WeakPropertyChangedProxy` hangs around forever instead! I could
reproduce this problem in unit tests, by accessing various internal
members through reflection -- asserting they were alive or not.

We do have another layer of indirection, where other objects are GC'd
that can free the `WeakPropertyChangedProxy`, such as:

    // Regular Binding
    ~BindingExpressionPart() => _listener?.Unsubscribe();
    // TypedBinding
    ~PropertyChangedProxy() => Listener?.Unsubscribe();

This means it would take two GC's for these objects to go away, but it
is better than the alternative -- they *can* actually go away now.

After testing apps with this change, sometimes I would get an
`InvalidOperationException` in `WeakReference<T>`:

https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs,103

So I added a parameter to `Unsubscribe(finalizer: true)`, to skip
`WeakReference<T>.SetTarget()` from finalizers.

After this change, I still found an issue! In my new unit test, the
following would hold onto a `ViemModel` object forever:

    VisualElement.BackgroundProperty.DefaultValue

This held the value of `Brush.Default`, in which
`Brush.Default.BindingContext` was the `ViewModel`!

My first thought was for `Brush.Default` to return `ImmutableBrush`:

    public static Brush Default => defaultBrush ??= new ImmutableBrush(null);

Because anyone could do `Brush.Default.Color = Colors.Red` if they liked.

When this didn't fix it, I found the underlying `_inheritedContext` is
what held a reference to my `ViewModel` object. I changed this value
to a `WeakReference`.

The types of leaks this fixes:

* Bindings to application-lifetime, singleton `ViewModel`s

* Scrolling `CollectionView`, `ListView`, etc. with data-bindings.

* Styles that were used on a `View` or `Page` that is now removed from
  the screen via navigation, de-parenting, etc.

Ok, I really think the leaks are gone now. Maybe?
@mohachouch
Copy link
Contributor

mohachouch commented Feb 22, 2023

As I said above. We have the same problem on Xamarin Forms on a large application. We have 15000 daily users for enterprise application. Xamarin Forms support is until May 2024. Please fix and don't forget Xamarin Forms users. @jonathanpeppers @jamesmontemagno @PureWeen @jsuarezruiz

@samhouts samhouts added the fixed-in-8.0.0-preview.1.7762 Look for this fix in 8.0.0-preview.1.7762! label Feb 23, 2023
@hosamyousof
Copy link

Hi @jamesmontemagno @PureWeen @jsuarezruiz @samhouts

Please, when we are going to have this update #13327 in .net 6 and .net 7??

@jsuarezruiz
Copy link
Contributor

As I said above. We have the same problem on Xamarin Forms on a large application. We have 15000 daily users for enterprise application. Xamarin Forms support is until May 2024. Please fix and don't forget Xamarin Forms users. @jonathanpeppers @jamesmontemagno @PureWeen @jsuarezruiz

Will take a look to move the changes to Xamarin.Forms.

@mohachouch
Copy link
Contributor

As I said above. We have the same problem on Xamarin Forms on a large application. We have 15000 daily users for enterprise application. Xamarin Forms support is until May 2024. Please fix and don't forget Xamarin Forms users. @jonathanpeppers @jamesmontemagno @PureWeen @jsuarezruiz

Will take a look to move the changes to Xamarin.Forms.

Thanks @jsuarezruiz

@AlasaliCS
Copy link

when will you update it for .net6 ? this is a serious and urgent problem need to be solved.
thank you

github-actions bot pushed a commit that referenced this issue Mar 2, 2023
Context: #12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

Reviewing memory snapshots in the above apps, sometimes I would see
new `WeakEventManager+Subscription` objects be created and never go
away.

I noticed the `WeakEventManager.RemoveEventHandler()` method did not
remove any `Subscription` entries that it encountered were no longer
alive.

I could reproduce this problem in a test, and improved an existing
test to check this collection is cleared appropriately:

    readonly Dictionary<string, List<Subscription>> _eventHandlers = new();
github-actions bot pushed a commit that referenced this issue Mar 20, 2023
Context: #12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

Reviewing memory snapshots in the above apps, sometimes I would see
new `WeakEventManager+Subscription` objects be created and never go
away.

I noticed the `WeakEventManager.RemoveEventHandler()` method did not
remove any `Subscription` entries that it encountered were no longer
alive.

I could reproduce this problem in a test, and improved an existing
test to check this collection is cleared appropriately:

    readonly Dictionary<string, List<Subscription>> _eventHandlers = new();
rmarinho pushed a commit that referenced this issue Mar 21, 2023
…() should clear subscriptions (#14074)

* [core] WeakEventManager.RemoveEventHandler() should clear subscriptions

Context: #12039
Context: https://github.com/Vroomer/MAUI-master-detail-memory-leak
Context: https://github.com/symbiogenesis/Maui.DataGrid/tree/memory-leak

Reviewing memory snapshots in the above apps, sometimes I would see
new `WeakEventManager+Subscription` objects be created and never go
away.

I noticed the `WeakEventManager.RemoveEventHandler()` method did not
remove any `Subscription` entries that it encountered were no longer
alive.

I could reproduce this problem in a test, and improved an existing
test to check this collection is cleared appropriately:

    readonly Dictionary<string, List<Subscription>> _eventHandlers = new();

* Remove the `n - 1` business

This is closer to the standard `forr` snippet that has been around forever, just using `n` instead of `i`.

* - add null forgiveness to test

---------

Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
@jsuarezruiz
Copy link
Contributor

As I said above. We have the same problem on Xamarin Forms on a large application. We have 15000 daily users for enterprise application. Xamarin Forms support is until May 2024. Please fix and don't forget Xamarin Forms users. @jonathanpeppers @jamesmontemagno @PureWeen @jsuarezruiz

Will take a look to move the changes to Xamarin.Forms.

Changes already available in latest Xamarin.Forms SR.

@samhouts samhouts modified the milestones: .NET 8 Planning, 8.0-preview1 Apr 6, 2023
@ToolmakerSteve
Copy link

"the amount of memory leaks, which makes the app completely unusable."

  • With and without vm.Bytes = null;, did you run until the app became sluggish? Without debugger attached? That is the only way to prove that it is truly a GC problem, not just "deferred GC".

  • Large memory allocations have always been problematic in .Net. Try a list of arrays, where each list element (one array) is small enough to fit on object heap. Behave similarly? If you null each list element, then do List.Clear(), does that help?

@ghost
Copy link

ghost commented Apr 15, 2023

Hello lovely human, thank you for your comment on this issue. Because this issue has been closed for a period of time, please strongly consider opening a new issue linking to this issue instead to ensure better visibility of your comment. Thank you!

@ghost ghost locked as resolved and limited conversation to collaborators May 16, 2023
@Eilon Eilon added the t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) label May 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
delighter fixed-in-8.0.0-preview.1.7762 Look for this fix in 8.0.0-preview.1.7762! legacy-area-perf Startup / Runtime performance p/0 Work that we can't release without partner/cat 😻 this is an issue that impacts one of our partners or a customer our advisory team is engaged with platform/windows 🪟 t/bug Something isn't working t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.)
Projects
None yet
Development

Successfully merging a pull request may close this issue.