How can I force garbage collection of a window? - wpf

I am trying to pro-actively ensure I am not causing memory leaks in my code by keeping an extra weak reference to an object, and checking it is no longer active when it should be released (this is conditional code so it only runs when I am testing).
To simply reproduce the effect I am seeing, create a new WPF Application and put a Button on the main window. Create another window, and put a TextBox on it. In the click handler for the button, put the following code:
Window1 w = new Window1();
WeakReference weak = new WeakReference(w);
w.ShowDialog();
w = null;
// Equivalent to Application.DoEvents() just in case...
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
GC.Collect();
GC.WaitForPendingFinalizers();
if (weak.Target != null)
MessageBox.Show("Memory Leak");
When you run this, click on the button and when the window displays, just click on the 'x' to close it and nothing happens - all good. Now do the same thing, but when the window displays, click into the TextBox and then click on 'x'. I get the "Memory Leak" message every time.
Ants Profiler shows System.Windows.Documents.TextEditor has a reference to the TextBox (which presumably gets set up only if you focus the TextBox), and the TextBox has a reference to the window. Its not a real memory leak because if you do the process multiple times, previous windows get collected, just not the latest. However, it means I cannot write tests that confirm memory is not leaking.
Am I the only person wanting this level of assurance, or is there another way?

I think some people have missed the point of your question. You're not trying to force GC's hand, but rather preemptively discover any memory leaks, and for that I applaud you.
In this particular case, it appears as though TextEditor (which is internal) is adding event handlers and has not yet had a chance to detach when your check runs. Have you tried explicitly shifting focus out of the closed window before pumping the dispatcher?
I think you will continue to run into these kind of issues if you attempt to do these tests in your application proper, rather than in the more controlled environment of integration tests, so perhaps you need to re-think your approach.

If previous instances get collected, it's not a memory leak. The garbage collector doesn't always take the most recent items, and it's by design. If you try to second-guess it you'll likely run into problems.
In a real memory leak items will accumulate without ever being reclaimed. That's something best detected using the profiler.

Windows are not just managed by your code but also by some WPF classes like Application. Calling Collect does not guarantee or prove anything, the window does get collected eventually.

try with DispatcherPriority.ContextIdle
Dispatcher.CurrentDispatcher.Invoke( DispatcherPriority.ContextIdle, new System.Action(delegate { }));

Related

WPF Modal dialog goes in background

I have problem with an application where modal WPF dialog occasionally goes behind the main application window. This hapens when I click button on the dialog which does some processing and updates controls (through binding) in the main application window. When it goes in background - clicking anywhere in the application brings it back into foreground.
var dialog = LoadDialogWindowThroughMEF();
dialog.Owner = Application.Current != null ? Application.Current.MainWindow : null;
dialog.ShowInTaskbar = false;
dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
return dialog.ShowDialog();
The above code shows how I open modal window. This happens very rarely.
Does anybody know what could be the problem?
I'm not sure I have an answer for you, but I can share some of my thoughts:
Every time I've encountered this type of problem, it happened because the Owner wasn't set properly. So, I'd try to not set the Owner and see if that makes the problem reproducible. You need to be absolutely sure that Owner is set to the correct parent window at all times1. You might also want to check that it is the actual MainWindow of your application that are supposed to be the parent. I think that most of the time it is beneficial to be explicit2 in your code. In this case that means that it is better to assign the known parent (maybe you have a reference to the parent somewhere that you could use), rather than relying on the Application.Current to provide you with that reference. Doing so will put you in control of the assignment to Owner. It could even make it possible to get rid of the ?: operator since you would have the means to control the reference even during unit testing.
I also want you to make sure that the code that is actually updating the parent window doesn't in any way force focus to a specific control on the parent window, or anything like that. (As long as the correct parent is set as Owner, I don't see this as a likely problem.)
I hope this helps you, but I understand if it doesn't. The fact that your dialog reappears when you click the parent window disproves some (or all!) of my points...
1 Except when running your unit tests, but that's a completely different matter.
2 As in the first meaning of the word according to wiktionary.org/wiki/explicit, and as opposed to implicit.

window closed event doesn't release memory and resource. How to solve the memory leak in WPF?

Recently I noticed serious memory leak in my WPF project. If simplify the project, it has a login form and a main form. In main form there are 1 user control which is composed of about 30 user controls and 3 buttons, 1 user control which has 3 buttons and a Infragistics datagrid. I use background worker to query DB every 30 sec only for the datagrid.
After I logout of the main form using main form.closed and re-launch the login window, I noticed that every time there is 6-7MB increase measured by ANTS memory profiler 7. Even though I have unregistered event handlers, set variables to null and called GC.Collect(), memeory leak is still the same. My questions are:
1. Why close wpf window doesn't release the memory and resource? I can see many strings(most of them are from GUI) are still in memory after close window by ANTs profiler.
2. Do I need to unregister the events defined by resource event setter? Do I need to unregister the events declared in XAML?
3. From WPF memory leak, people said we should not use GC.Collect(), but I do see a little improvement. Shall we use it or not?
I have had a simillar problem while using WindowsFormsHost for PictureBox control.
The WPF window using WF PictureBox control could not be fully released and that's why i had a regular ~10mb increase everytime i re-opened the subwindow.
The problem was solved since i started nulling the WFH object on WPF window closing.
Just make sure You clear all the WF controls if You use such.
Break into the debugger and then type this into the Immediate window:
.load C:\Windows\Microsoft.NET\Framework\v2.0.50727\sos.dll
The path to sos.dll varies. The way to find out the correct path is to look for mscorwks.dll in the Modules pane. Wherever that is loaded from is the correct path for sos.dll.
Then type this:
System.GC.Collect()
That will ensure anything not reachable is collected. Then type this:
!DumpHeap -type <some-type-name>
This will show you a table of all existing instances, with addresses. You can find out what is keeping an instance alive like this:
!gcroot <some-address>
originally answered by Daniel
It depends. User controls in WPF do not inherently dispose, so you will have to override the functionality and allow it in your controls with:
http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx
But to your point, you will need to do a GC.Collect() at least once as SlimGG suggests.
In most cases, calling the garbage collector directly is considered bad practice because it is not calling it for your control specifically, but for all objects queued for disposal.

WPF performance problem with CommandManager

We've created a new, quite complex, WPF application from the ground up and have run into a performance problem as the number of commands registered with the CommandManager increase. We're using simple lightweight commands in our MVVM implementation, however the third party controls we're using (Infragistics) do not, and call CommandManager.RegisterClassCommandBinding liberally to add RoutedCommands. The performance problem manifests itself as a perceived sluggishness in the UI when responding to user input, for example tabbing between controls is slow, text input is 'jerky' and popup animation is 'clunky'. When the app is first fired up the UI is snappy. As more screens containing Infragistics grids are opened the performance deteriorates.
Internally, the CommandManager has a private field named _requerySuggestedHandlers, which is a List< WeakReference>. I've used reflection to get a reference to this collection, and I've noticed that when I call .Clear(), the responsiveness of the UI improves back to its initial state. Obviously I don't want to go round clearing collections that I know little about, especially using reflection (!) but I did it to see if it would cure the performance problems, and voila it did.
Normally, this situation would clean itself up after a certain amount of time passes. However, the collection of WeakReferences (_requerySuggestedHandlers) will only get trimmed once a garbage collection is initiated, which is non-deterministic. Because of this, when we close down windows containing grids (Infragistics XamDataGrid), the CanExecute property for 'dead' grid commands continue to be evaluated unnecessarily, long after the window is closed. This also means that if we close down a number of windows, the performance is still sluggish until a garbage collect is initiated. I understand that this can happen on allocation, and I've seen that myself because if I open a further window this causes the initial memory (from the disposed Windows) to be collected and performance returns to normal.
So, given the above, here are my questions:
How, and from where, does CommandManager.InvalidateRequerySuggested() get called? I haven't found any documentation on MSDN that explains this in any great detail. I hooked up to the CommandManager.RequerySuggested event and it looks like it's being called whenever controls lose focus.
Is is possible to suppress CommandManager.InvalidateRequerySuggested() being called in response to user input?
Has anyone else run into this issue, and if so, how have you avoided it?
Thanks!
This sounds like one of the rare cases where deterministically calling GC.Collect() is the right thing to do. The ordinary argument against it is that the garbage collector is smarter than you are. But when you're dealing with WeakReference objects, you enter territory where you may know something that the garbage collector doesn't. Kicking off garbage collection is certainly better than clearing _requerySuggestedHandlers - among other things, it won't do anything to the WeakReference objects that point to controls that are still alive.
I'd choose this over trying to figure out how to suppress RequerySuggested, since that would screw up the behavior of those commands that you still care about.

WPF parent-child window: binding reference problem

I have a WPF Window that open a modal child window to load some data. Both window have a own viewmodel, now I have this problem: after I close the child window it seems still running in background!
To close the child window I set DialogResult from viewmodel command; now, if I create a new data and then I edit it from parent window (with the child window closed before), the child window still capture the property changed event for the properties previously bind.
How can avoid this?
I would clear every reference with data when I close modal window. Which is the best practise to do it?
Ensure that you don't keep any references to your window, even an indirect one. One of the most common cause of leaks are events. If a window B is adding an event handler to an event of window A, B won't be released until A is also.
For example, if you're directly listening to property changes, you should use the Weak Event Pattern and replace all your += with a call to PropertyChangedEventManager.AddListener. In general, every strong handler you add to an event should be removed to avoid leaking.
More information about leaks in .NET in this MSDN article.
You can use a memory profiler like Scitech's mem profiler or Jetbrains dotTrace to see what ojects are keeping your windows in memory.
Edit: In response to your comments, your case is really simpler than I first thought: the Garbage Collector simply didn't collect the window yet. Adding GC.Collect on Test_Click for testing purposes solves the issue.
Here, remove the SelectionChanged event from the ComboBox when the form is closing so you can let the GC do its job and reclaim the form later without having problems. If you really need the whole form to get released right now, you might consider calling GC.Collect although you should avoid it when you can.
Edit 2: In response to your third comment, it should only matters for objects that are shared between views, and where the changes in the view will change something back in a shared object. In your test project the SelectionChanged does nothing on the original list so it doesn't really matter if the event is raised or not. The form will get collected eventually.

WPF-application memory leak

After certain action (pressing a button that starts a sequence of calculations) in the WPF-application a memory leak occurs (it is visible in the task manager in vm size section) approximately on 10 mbytes after each pressing of the button.
The sequence of calculations does not contain errors.
The use of memory profiler (.NET Memory Profiler) has shown that leaks in .net are not present, but after each pressing of the button the memory size shown in Name/Resource section (marked HeapMemory) increases approximately by 10 mbytes.
I've read posts about leaks in WPF but those are not my case definately.
What can be wrong? Any suggestions? Maybe, someone had the same problem?
Seeing an increase in the used memory is a misnomer in .NET for detecting a memory leak.
It is easy to make a memory leak in WPF, however. I would suggest using a slightly more visual tool like Redgate Ants Memory Profiler (14 day free trial). Use this method to test for leaks:
Press the button once (to eat up any warmup you might have)
Take a snapshot
Press the button again
Take a snapshot
When you go to the "Class List" and check the filter for "From current snapshot show: only new object". This should give you a better picture of whether you have objects that will never be let go.
The other thing about Ants Memory Profiler is that it has links to videos everywhere that instruct you on how to find a leak. Tracking down leaks is a bit of a black art and it's nice to have help.
No, I don't work for Redgate :)
Perhaps you need to use the WeakEvent Pattern as documented on MSDN to avoid leaks?
Listening for events can lead to memory leaks. The typical technique for listening to an event is to use the language-specific syntax that attaches a handler to an event on a source. For instance, in C#, that syntax is: source.SomeEvent += new SomeEventHandler(MyEventHandler).
This technique creates a strong reference from the event source to the event listener. Ordinarily, attaching an event handler for a listener causes the listener to have an object lifetime that influenced by the object lifetime for the source (unless the event handler is explicitly removed). But in certain circumstances you might want the object lifetime of the listener to be controlled only by other factors, such as whether it currently belongs to the visual tree of the application, and not by the lifetime of the source. Whenever the source object lifetime extends beyond the object lifetime of the listener, the normal event pattern leads to a memory leak: the listener is kept alive longer than intended.
(My emphasis.)
I could fix WPF Application memory leak issue by inserting in "thin" places GC.Collect().
Hope this help!

Resources