This repository has been archived by the owner on May 1, 2024. It is now read-only.
[Bug] VisualStateManager memory leak when set in a global ResourceDictionary #14815
Labels
Projects
Description
VisualStateManger (VSM) creates a memory leak when set in a ResourceDictionary added to Application's resources (e.g.
Application.Current.Resources.MergedDictionaries.Add(new StyleResources());
)For example, say you have a ResourceDictionary that holds application-wide styles and styleclasses. And in this dictionary you have a 'RedButton' styleclass that utilizes VSM. Any page that uses this 'RedButton' styleclass will leak.
Xamarin.Forms/Xamarin.Forms.Core/VisualStateManager.cs
Line 25 in e3faa59
We believe we have found the source of this leak in the previous link. In VSM's code, line 25, there is a 'VisualStateGroupsPropertyChanged' handler that sets the VisualStateGroupList's VisualElement to null when the VisualStateGroups property changes. This is the only place it gets set to null. So in the instance of VisualStateGroup being set in a global ResourceDictionary that doesn't get collected until the end of the application, nothing's triggering that VisualStateGroupsPropertyChanged handler upon leaving the page, meaning the VisualStateGroup hangs out in memory resulting in the memory leak.
Note: as demonstrated by my linked sample project below, setting a VSM at page/control level does not lead to memory leak. This is likely because when the page/control gets collected, it must trigger VisualStateGroupsPropertyChanged, cleaning up the VisualStateGroupList.
Another note: Setting a blank VSM in a global ResourceDictionary will not cause the memory leak for us. The VSM must have states defined in it for the leak to occur. Again, this points to the issue being with VisualStateGroupsPropertyChanged as a blank VSM (in our case at least) does not trigger any changes, therefore VisualStateGroupsPropertyChanged doesn't get hit, resulting in no VisualStateGroupList getting set (so there's nothing to collect).
To demonstrate the above note, the following code does not leak.
But this one does leak
Steps to Reproduce
Note: in our (closed-source) app, navigating away from a leaky page then later back to it will deconstruct the first instance of this page. I was not able to re-create that in my sample project...our navigation service must have handled multiple instances of a page. To be safe however, when testing, I recommend navigating to the leaky page just once, and navigating between other pages to build pressure and see if the leaky page collects.
Basic Information
Environment
Show/Hide Visual Studio info
Reproduction Link
https://github.com/jsclay/VSGMMemoryLeak.git
Workaround
While not yet attempted, the most likely workaround is using Triggers instead of VisualStateManger.
The text was updated successfully, but these errors were encountered: