benruehl / adonis-ui

Lightweight UI toolkit for WPF applications offering classic but enhanced windows visuals
https://benruehl.github.io/adonis-ui/
MIT License
1.71k stars 143 forks source link

Ripple layer appears to be leaking memory #43

Closed Mgamerz closed 4 years ago

Mgamerz commented 4 years ago

Describe the bug The Ripple layer in RippleHost appears to be leaking memory through it's event handlers. I am using it with a customized version of Extended WPF Toolkit and my busy hosts are not being freed from memory, and after using dotMemory, RippleHost is holding references to the control even though the control was already disposed.

To Reproduce While I do not have a fully reproducible sample on hand, I think I have found the issue (or at least, what causes the initial event handler to be set that is not unset.

  1. Setup a project with Extended WPF and Adonis UI (and the theme controls)
  2. Make a BusyContentHost item that has a button in it and display it
  3. Set busycontent to null and do a garbage collection
  4. The busy content control remains in memory because an event handler in RippleHost is holding a reference that is not cleared

Expected behavior The ripple layer should remove it's event handlers when the host is disposed. I am not entirely sure where this is performed.

Screenshots In RippleHost.cs, when I commented out the lines setting the ParentWindowOnDeactivated and PreviewMouseLeftButtonUp, my objects were properly garbage collected. image

I have a memory analyzer I build into my apps to help identify things not being freed (before I take it to dotMemory), and after commenting it out, I can see things being garbage collected (in this pic it was automatic - I didn't even clear it yet): image

I made a video to demonstrate the issue, where memory is not freed/is freed before and after commenting out the addition of the handlers.

https://youtu.be/1Jygs0Xoaus

I don't think this is exclusive to Extended WPF Toolkit, it's just what I am using. A busy host is essentially an user control that appears in an overlay.

Additional context The repo in question is https://github.com/me3tweaks/me3tweaksmodmanager. I have your library in there (slightly customized colors and a few other things like fixing the listbox ripple). In order to bring up this dialog you would need a mod (and a mass effect game) so I am not sure it is something you can easily do.

benruehl commented 4 years ago

Thanks a lot for this very detailed report. I will try to setup an environment that reproduces the issue and see if I can find a solution.

benruehl commented 4 years ago

I finally found some time to look into this, but unfortunately I am not able to reproduce the behavior.

I created a new window containing a BusyIndicator (Xceed.ExtendedWpfToolkit), a RadioButton and a Button. This seems to be the setup in the video, too. I launched the app in dotMemory and took a snapshot before opening the window, when the window is open, and after closing the window. Comparing the snapshots shows me that the window instance gets created and deleted just fine.

Maybe there is something wrong with this approach? Am I missing something? Unfortunately, I cannot test your app directly because I do not own a copy of Mass Effect. Is there a way I can fool your app around me having no Mass Effect installed? Maybe I could insert some test data in order to bring up the dialog?

In case I could reproduce the memory leak, I would try to call ClearRippleLayer() when the parent window gets closed. But I need a reproducable way to verify that this approach works. I cannot just add it hoping it does what I expect.

benruehl commented 4 years ago

Closing this because it could not be reproduced.