My WPF application leaks memory at about 4kb/s. The memory usage in Task Manager climbs constantly until the application crashes with an "Out of Memory" exception.
By doing my own research I have found that the problem is discussed here: Track down memory leak in WPF and #8 here: http://blogs.msdn.com/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx
The problem described is:
This is a leak in WPF present in versions of the framework up to and including .NET 3.5 SP1. This occurs because of the way WPF selects which HWND to use to send messages from the render thread to the UI thread. This sample destroys the first HWND created and starts an animation in a new Window. This causes messages sent from the render thread to pile up without being processed, effectively leaking memory.
The solution offered is:
The workaround is to create a new HwndSource first thing in your App class constructor. This MUST be created before any other HWND is created by WPF. Simply by creating this HwndSource, WPF will use this to send messages from the render thread to the UI thread. This assures all messages will be processed, and that none will leak.
But I don't understand the solution!
I have a subclass of Application that I am using and I have tried creating a window in that constructor but that has not solved the problem.
Following the instructions given literally, it looks like I just need to add this to my Application constructor:
new HwndSource(new HwndSourceParameters("MyApplication"));
The fix:
Application.xaml.cs
class MyApp1 : Application
{
// ...
public Application()
{
new HwndSource(new HwndSourceParameters());
}
// ...
}
Related
I just need a little help to clarify how the Messenger class works with ICleanup in MVVM-Light. I am creating a WPF 4 application in VB.Net with Mvvm-Light v4.
I have a messenger that registers for a message sent from a NavigationService Class I created as follows:
This is the registration in the ViewModel named ClientListViewModel
''register for messages
Messenger.[Default].Register(Of INavigationService)(Me, "NavigationStart", False, AddressOf HandleParentChildNavigate)
This receives the NavigationService class and performs a check on it based on some other logic that is not relevant to this question.
The message is sent when a navigation event is triggered in my NavigationService class as follows
''Send message that navigation has been requested
Messenger.Default.Send(Of INavigationService)(Me, "NavigationStart")
This allows me to cancel the navigation event if my receiving class (in this case ClientListViewModel) has data validation errors, and it returns the focus to the record with errors. This all works great.
My question is, where and how do I unregister the message. I know that I need to in order to avoid memory leaks as I read on other posts. I have seen something like the following:
Public Overrides Sub CleanUp()
Messenger.Default.Unregister(Me)
End Sub
This cleanup is in the same viewmodel (CientListViewModel) the receives the message.
So I have three questions:
When should I call this cleanup method
Is ther a way with the ViewModelLocator to unregister all message recipients when the application is closed down?
This question is less relevant but I would appreciate some help too, How do I tell if I am getting "memory leaks" as a result of unregistered message recipients?
Thanks for your time
When viewmodels should be "cleaned up" depends on your application and viewmodels usage. For example, I work on application with tabbed interface. When user closes tab application calls cleanup on viewmodel representing that tab (which itself goes through its viewmodels and calls cleanup on them as well). So the general rule - as soon as you don't need viewmodel anymore - you should cleanup it (closing child window, tab, etc.) As for the other questions:
2) It is indeed doesn't matter on application closing if you cleanup your viewmodels. As on closing all memory will be freed up and you don't get memory leaks :)
3) You should check application memory usage. In our application we had serious problems (and actually still have but not that big) with memory leaks. We determined that we could have leaks by memory tracking: opened/closed many tabs, called GC.Collect() - but memory usage didn't go down. We started to track memory leaks with WinDbg and found literally lots of places where we didn't unregistered recipients from Messenger. Also, we're using and old version of MVVM Light which is bound to CommandManager so we had problems with RelayCommands as well.
Moral is - you should think about cleaning up resources during programming as later it can be painfull to find and fix it.
I've not used the Messenger in MVVM-Light so I do not know if there is an inherent way to cleanup. Here are some general answers to these questions:
You should do your cleanup when you no longer need to know about the message or when no longer need your view model. If the Navigate is not canceled does your ViewModel care about the Navigate message any more (i.e. is it getting unloaded or is the view it supports going away)? If that is the case then you could unregister when you receive the Navigate command and have determined it is OK to navigate.
This I do not know. But on app close it shouldn't matter (for managed objects, see below).
You shouldn't need to worry about these memory leaks with managed objects when the app shuts down, any non-referenced objects will be trashed when the whole app domain is terminated. If you have unmanaged resources being referenced this is another story.
Working with WinForms you have to free memory after using gdi objects, event handlers, objects from native code, etc.
In WinForms I used to remove for example event handlers in the dispose method.
What is the best workaround to prevent memory leaks in Wpf? Is it the same as in Winforms using Dispose pattern? At all, do I have to care about event handlers, gdi objects in Wpf? What about the runtime created resources(Brushes, etc)?
This blog post lists the most common situations that cause memory leaks in WPF applications.
Event handlers to objects in parent windows
Registering to events from static objects
Using timers
Data binding
Changing the Text property of a text box
It also describes how to fix these common issues.
Another good approach is to develop an app while following the standard guidelines and then use some kind of profiler to determine any memory leaks or performance bottlenecks.
From MSDN: Any WPF framework-level element (those objects deriving from either FrameworkElement or FrameworkContentElement) has three common lifetime events: Initialized, Loaded, and Unloaded.
.....
Unloaded is raised last and is initiated by either the presentation source or the visual parent being removed. When Unloaded is raised and handled, the element that is the event source parent (as determined by Parent property) or any given element upwards in the logical or visual trees may have already been unset, meaning that data binding, resource references, and styles may not be set to their normal or last known run-time value.
Some helpful links on WPF resource dictionary leaks:
DynamicResource\StaticResource cause memory leaks
Memory leak problem with ResourceDictionary and MergedDictionaries
Watch out for events: it's very easy to miss something, because all references from the delegate will exist until the delegate lives. I suggest to use weak event pattern when it's possible. Actually Microsoft uses it in their Prism framework.
http://msdn.microsoft.com/en-us/library/aa970850.aspx
Also check out an issue that I was catched by many times when learning WPF http://support.microsoft.com/kb/938416/en-us
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.
Scenario:
The VB 6 form has a InteropControl (WinForms).
The InteropControl has a ElementHost
The ElementHost has my WPF control
Everything seems to be working except that Application.Current seems to be null when I need it. All I really want to do is hook into the unhandled exception event before the first form is fully displayed.
In this scenario is a WPF Application object ever created?
If so, when it is created?
If not, what causes messages to be pumped?
What would happen if I started the Application object on a background thread?
First I will explain how message loops work in interop scenarios, then I will answer your questions and give a few recommendations.
Message loop implementations in your scenario
Your scenario involves three separate technologies: VB 6, WinForms, and WPF. Each of these technologies is implemented on top of Win32. Each has its own GetMessage()/DispatchMessage() loop to pump Win32 window messages.
Here is where each GetMessage()/DispatchMessage() loop is implemented:
VB 6 implements it internally
WinForms implements it in System.Windows.Forms.Application
WPF implements it in System.Windows.Threading.Dispatcher
WPF Application object is optional
Your question assumes that WPF implements the message loop in the Application object. This is not the case. In WPF, all essential functions that WinForms handled in the Application object have been moved to other objects such as Dispatcher, HwndSource, InputManager, KeyboardDevice, MouseDevice, etc.
In WPF the Application object is completely optional. You can construct a complete WPF application with a complex UI without ever creating an Application object. An application object is only useful if you need one of the services it provides, for example:
A common ResourceDictionary
Mapping WM_APPACTIVATE message into Activated and Deactivated events
Mapping WM_QUERYENDSESSION message into OnSessionEnding event
Lifecycle management (Startup/Run/Shutdown/Exit)
Automatic shutdown when the last window or main window closes
Default icon for WPF windows
Remembering the first window opened (MainWindow)
Common registration for NavigationService events (Navigated, etc)
StartupUri
The Application class also provides several useful static members such as FindResource, GetResourceStream and LoadComponent that don't require an Application object to exist.
When you call Application.Run(), all it does is:
Install the mechanism to handle WM_APPACTIVATE and WM_QUERYENDSESSION, and
Execute Dispatcher.Run()
All of the actual message loop functionality is in Dispatcher.Run().
Registering for unhandled exceptions in WPF message loop
The Application.DispatcherUnhandledException event you were trying to use is a simple wrapper around the Dispatcher.UnhandledException event. I think they included it in the Application object because WinForms programmers expected it to be there, but your question shows that this may have backfired.
To register for unhandled exceptions from WPF's Dispatcher, all you have to do is:
Dispatcher.Current.UnhandledException += ...;
Unlike Application.Current, Dispatcher.Current cannot be null: If you access Dispatcher.Current from a thread that doesn't yet have a Dispatcher, one will be created automatically.
Once you have subscribed to Dispatcher.UnhandledException, any unhandled exception from a Dispatcher message loop on the current thread will cause your event handler to be called. Note that this only applies to unhandled exceptions when Dispatcher.Run() is pumping messages: When another technology such as VB 6 or WinForms is pumping messages, that technology's exception handling mechanism will be used instead.
WPF message loop also optional
Not only can WPF run without creating an Application object, it can also function without Dispatcher.Run(), as long as another technology is pumping Win32 window messages. This is done by creating a dummy window and/or subclassing a WPF window to install a message hook. Thus no matter what message loop is pumping messages, WPF will work as expected.
In fact, when you use ElementHost, the WPF Dispatcher is not used for message pumping unless you use one of the following methods:
Window.ShowDialog
Dispatcher.Invoke
Dispatcher.Run (or equivalently, Application.Run)
DispatcherOperation.Wait
Because of this, your WPF exception handler will probably not be called. Instead you will need to install your exception handler at the VB 6 or WinForms level.
Answers to your questions
In this scenario is a WPF Application object ever created?
No.
If not, what causes messages to be pumped?
VB 6 is pumping the messages.
What would happen if I started the Application object on a background thread?
Very little:
If you have application resources these would be created on the background thread, possibly leading to exceptions when they are used on the main thread.
If you add a handler to Application.Current.DispatcherUnhandledException it would only apply to the background thread. In other words, the handler will never be called unless you create windows on the background thread.
Your Application.Startup will be called from the background thread, which is probably a bad thing. Ditto for StartupUri.
Recommendation
From what you are asking it sounds like you are getting an unhandled exception during the loading of your WPF control and you want to catch that exception. In this case, the best plan is probably to wrap your WPF control inside a simple ContentControl whose constructor uses code like this to construct the child:
Dispatcher.Current.UnhandledException += handler;
Disptacher.Current.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() =>
{
Content = CreateChildControl();
Dispatcher.Current.Invoke(DispatcherPriority.ApplicationIdle, new Action(() => {});
});
How it works: The BeginInvoke delays construction of the child until VB 6 and/or InteropControl have completed all processing. The Invoke call after the child control is created invokes an empty action at low priority, causing all pending DispatcherOperations to complete.
The net result is that any exceptions that were thrown within or just after the constructor are now passed to your exception handler.
In WPF, the Application object is not directly responsible for the message pump, it is the Dispatcher. When you start a WPF app, Application.Run() is called at startup, which calls Dispatcher.Run().
In your interop scenario, Application.Current will return null since it is never created. Message pumping is handled by VB, since it creates the main window. If you rely on it in your code you can either:
Create a new Application object:
if (Application.Current != null)
{
new Application();
}
Application is a singleton, so it will be automatically stored in Application.Current.
Avoid relying on it whenever possible (which I think is the recommended way). You should note that many of the services this class provides (e.g. the Exit event) will not be available in your scenario anyhow. If all you need is the unhandled exception event, you can use Dispatcher.CurrentDispatcher.UnhandledException.
Is there any way to get the UI thread's Dispatcher when you have no reference to any UI elements?
You can grab the UI Dispatcher from the static application instance: Application.Current.Dispatcher
You may want to check Application.Current for null first, as it can be cleared during a shutdown sequence.
The following works much better for me when being used in a WinForms application that happens to be also using WPF (in my case Esri's Arcmap.exe)
private System.Windows.Threading.Dispatcher Dispatcher { get; set; }
// I put this in my view model constructor as it MUST be called from UI thread
Dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
The other method (which involved calling new System.Windows.Application() to populate System.Windows.Application.Current) caused issues for me every time I opened a new WPF window and then closed it. Not only did this null out System.Windows.Application.Current, but I could no longer open up new windows as their InitializeComponents() methods, all failed with:
System.InvalidOperationException: 'The Application object is being
shut down.'
So far the new solution is working without those side effects.