Open marbel82 opened 2 years ago
@marbel82 Does it still refer to the Effect after you release LeakWindow?
The Effect (DropShadowEffect) is in App.Resources. The border adds an event handler, so an event handler keeps a reference to the border.
I don't keet a reference to the LeakWindow, I just create it, invoke Show() and than close it.
When I added a finalizer to LeakWindow and VolatileWindow you can see that only VolatileWindow finalizer is invoked.
I update my example to run without debugging. This you can see in the Release build configuration:
Does the bug reproduce also in WPF for .NET Framework 4.8?: I don't know
Problem description: I define DropShadowEffect in global Application.Resources> in App.xaml, and I use it for a Border.Effect property. The Border is in some Window. All windows I created and closed stay in memory.
I found that the Window object is is held by the Border, and the Border is held by an EventHandler, and the EventHandler is held by DropShadowEffect. EventHandler has reference to EffectChanged method.
I think I have found the problem. When an
UIElement.Effect
property is assigned, the setter (Visual.VisualEffectInternal.set
) adds strong event handler forEffectChanged
methodhttps://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Media/Visual.cs,2976 From ILSpy
Event handler is removed only if an Effect property is changed. (Am I wrong?)
Analyzing this code, you can see that the event handler has not been added when the Effect object is frozen (IsFrozen=true).
I found a page, on which was written how to switch IsFrozen in XAML.
https://docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/freezable-objects-overview?redirectedfrom=MSDN&view=netframeworkdesktop-4.8#freezing-from-markup
But, it's not working.
One solution to the memory leak I have found is to define each DropShadowEffect localy in a Border.
Actual behavior: Effect setter (System.Windows.Media.Visual.VisualEffectInternal.set) use strong reference for event handler.
Expected behavior: Effect setter (System.Windows.Media.Visual.VisualEffectInternal.set) should use weak reference for event handler (e.g. WeakEventManager)
Minimal repro: https://github.com/marbel82/UIElementEffectMemoryLeakRepro
Click [Create LeakWindow], close the Window, click GC.Collect, Pause Visual Studio, Memory Usage/Take Snapshot and find LeakWindow