-
Notifications
You must be signed in to change notification settings - Fork 138
Description
I have encountered a significant memory leak when using the Toast system. When displaying and closing a large number of toasts, the memory usage grows continuously and is not reclaimed by the GC.
Using dotMemory, I identified that ResourceDictionary and ControlTheme are retaining thousands of StyleInstance and DisposeAnimationInstanceSubject objects, which in turn keep the ToastCard controls alive.
Reproduction Steps
- Open
ToastDemoViewModel.cs. - To simplify the experiment, modify the
ShowNormalmethod (change toasync voidand add a loop):for (int i = 0; i < 1000; i++) { ToastManager?.Show( new Toast("This is message"), showIcon: ShowIcon, showClose: ShowClose, type: notificationType); await Task.Delay(10); }
- Run the
Ursa.Demoproject. - Click the
Informationbutton. - Observe the memory usage.
Results
Memory usage grows by hundreds of MBs and is never released.
Probable Cause
The issue lies in Ursa.Themes.Semi/Controls/Toast.axaml.
Currently, animations are applied via a nested Style targeting a template part (PART_LayoutTransformControl) with FillMode="Forward".
<Style Selector="^ /template/ LayoutTransformControl#PART_LayoutTransformControl">
<Style.Animations>
<Animation
Easing="QuadraticEaseIn"
FillMode="Forward"
Duration="0:0:0.3">
...
</Animation>
<Animation
Easing="QuadraticEaseIn"
FillMode="Forward"
Duration="0:0:0.15">
...
</Animation>
</Style.Animations>
</Style>
It seems that StyleInstance created for the template part fails to release the animation subscription when the control is removed from the visual tree, causing the leak.
I compared this implementation with NotificationCard.xaml from the standard Avalonia Fluent Theme:
Avalonia.Themes.Fluent/Controls/NotificationCard
In the Fluent theme, the entrance animation is defined directly in ControlTheme.Animations (targeting the control itself, not a template part):
<ControlTheme.Animations>
<Animation Duration="0:0:0.45" Easing="QuadraticEaseIn" FillMode="Forward">
...
</Animation>
</ControlTheme.Animations>Proposed Fix
If we move the animation from the nested style selector directly to the root ControlTheme.Animations, the garbage collection works as expected.
However, this change definitely changes the animation's behavior, and if it's expected and satisfactory, we can apply this fix. Otherwise, need to explore other options.