Ok,
So I have a method which fires when someone clicks on our Icon in a silverlight application, seen below:
private void Logo_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
ShowInfo(true);
DispatcherTimer autoCloseTimer = new DispatcherTimer();
autoCloseTimer.Interval = new TimeSpan(0, 0, 10);
autoCloseTimer.Tick +=new EventHandler((timerSender,args) =>
{
autoCloseTimer.Stop();
ShowInfo(false);
});
autoCloseTimer.Start();
}
Whats meant to happen is that the method ShowInfo() opens up a box with the company info in and the dispatch timer auto closes it after said timespan. And this all works...
But what I'm not sure about is because the dispatch timer is a local var, after the Logo_MouseLeftButtonUp method finishes, what is there to keep the dispatch timer referenced and not availible for GC collection before the anonymous method is fired?
Is it the reference to the ShowInfo() method in the anonymous method?
Just feels like some thing I should understand deeper as I can imagine with using events etc it can be very easy to create a leak with something like this.
Hope this all makes sense!
Andy.
The DispatcherTimer registers itself with the Dispatcher by calling the internal Dispatcher.AddTimer method when you call Start.
Since it also unregisters itself by calling Dispatcher.RemoveTimer when you call Stop, you won't leak memory.
The Timer keeps the anonymous method alive in its Tick event, which also keeps the variables in the method alive through the closure.
One of the more obscure causes of memory leaks in .NET is event handlers. An event handler is a reference to an object, and keeps the object in scope. When you're done with an event handler, it needs to be dropped. If the event handler is used only once, it can deregister itself, but if it gets used more than once, there will need to be some other object that knows when it's no longer useful, and drops the event handler.
Related
For work, I have to subscribe to an external event and handle it when it comes by. I have no problem doing all that but I noticed that after the first GC pass, the event handler I added seemingly gets removed. I won't be able to receive the next event after the collection.
If I manually trigger the GC then remove and add the handler, I will properly receive the next event.
I tried using KeepAlive and SuppressFinalize from the GC to no avail. I also tried to add the handler as a lambda, but it still gets removed after the first garbage collection.
example code (pseudo, for reference only)
private externalLibrary.Server server = new Server();
private externalLibrary.DataHandler handler; //delegate is assigned in constructor
public bool Subscribe(){
//...
server.Data.Received += handler;
}
With this setup, I receive events until the first GC.
My ugly workaround looks like this:
ResetHandler(){
server.Data.Received -= handler;//It seems to already be removed by GC but better be safe than sorry
server.Data.Received += handler;
}
And in the code when I finished my processing of the event, I do:
GC.Collect;
ResetHandler();
This allows me to circumvent the problem. I would like to find a better solution or know what I am doing wrong.
Please note that this is my very first question here.
Thank you for your input.
I have a rather short question about anonymous event handlers:
This is the code that I have:
public void AddTestControl(Control ctrl)
{
ctrl.Disposed += (o, e) => { RemoveTestControl(ctrl); };
ctrl.SomeEvent += _Control_SomeEvent;
}
public void RemoveTestControl(Control ctrl)
{
ctrl.SomeEvent -= _Control_SomeEvent;
}
Is this code above fine, or should the code be rewritten in order to remove the Disposed Event Handler?
Something like this:
public void AddTestControl(Control ctrl)
{
ctrl.Disposed += _Control_Disposed;
ctrl.SomeEvent += _Control_SomeEvent;
}
public void RemoveTestControl(Control ctrl)
{
ctrl.Disposed -= _Control_Disposed;
ctrl.SomeEvent -= _Control_SomeEvent;
}
Generally, the only situation where you need to remove the event handlers from an object in order for it to be eligible for garbage collection is when the publisher object (the one defining the event) lives longer than the subscriber object (the one containing the event handlers). In such a situation the GC won't be able to release the subscriber when it goes out of scope since it's still being referenced by the publisher.
In this case, assuming this is WebForms or WinForms, the publisher (that is the Control object), is most likely a child object of the subscriber (probably a Page or a Form), which will be the first to go out of scope taking all its associated objects with it. Hence there's no need to remove the event handlers.
It always feels cleaner to me to unsubscribe from events, even in situations where I know the subscribers always outlive the publisher (the object raising the event): the event will never be raised again, the publisher is no longer reachable and can be collected.
Then again, how many people go to the trouble of unsubscribing every event handler in e.g. a WinForms application? The object references point from the publisher to the subscribers, not the other way around, so the publisher can be collected while the subscribers live on. It doesn't present the same danger as the opposite situation, where a long-lived publisher (e.g. a static event) can wastefully keep potentially large subscribers alive long after they could have been collected.
If you want/need to unsubscribe, then the requirement to unsubscribe the same delegate makes anonymous event handlers a bit of a pain. The Reactive Extensions solve this problem in a neat way: rather than having to remember the delegate you subscribed, subscribing returns an IDisposable which unsubscribes when disposed. Chucking all your subscriptions into a CompositeDisposable lets you unsubscribe everything with just one Dispose call.
Both codez are fine, but I like second as a matter of personal preference. It reads clearer than the first.
On top of it with the first code, there's anonymous lambda delegate and it gets a current reference to ctrl. That code may behave unexpectedly depending on situation and compile optimisation settings: whether or not the call is inlined or not.
Not to mention that there's architectural problem with the code: you have ControlOwner and a bunch of Child Controls. I take it you're adding child controls to ControlOwner at runtime, and then trying to react to their behavivour by subscribing ControlOwner to the childControl events. This is fine for events like _ButtonClicked etc. But not good for Dispose. Let the child control handle it's disposing on itself, the OwnerControl doesn't need to know about it. Not to mention that it may not exist at a time ChildControl[n].Dispose is called.
In short:
* it is better to leave dispose event on ChildControl alone and do all clean up in ChildControl.Dispose
* it is not necessary to unsubscribe from events. Event dispatcher will check if subscriber is alive.
When using the FormClosing event, why does the code e.Cancel = true; work, but new CancelEventArgs().Cancel = true; does not work?
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
new CancelEventArgs().Cancel = true;
}
The event is raised by the Winforms plumbing code. The only way it can see that the custom event handler wants to alter the default behavior is through the e object. Creating a new CancelEventArgs object has no side-effects that the plumbing can detect.
There's something else wrong, events are raised for the benefit of external code, letting it know what's going on and giving it an option to alter behavior. There is no external code here, the event handler is actually part of the same class that raises the event. In other words, the form is listening to its own events. There's a much better way to deal with that, you override the method that raises the event. Like this:
protected override void OnFormClosing(FormClosingEventArgs e) {
e.Cancel = true;
base.OnFormClosing(e);
}
Now external code can override the default behavior, events are raised after the OnXxxx method runs. And you have a choice, if you do not want the external code to override the behavior, simply swap the two statements.
I think the code is doing exactly what it says; what's missing is a literal reading of it.
When you assign a new value to e.Cancel, you are modifying the e that is provided as a parameter to the function. After the event handler function finishes, this FormClosingEventArgs instance, including any changes made to it from within the event handler, will be available to whatever code invoked the event handler. In this case, that's almost certainly the Winforms code written by Microsoft.
On the flip side, when you inside that event handler create a new instance of the type FormClosingEventArgs and do something to it, there is nothing to provide that information back to the caller; you'd need something explicit for that. Since the caller is looking at the value of the parameter it passed in once the event handler completes, you'd need to somehow replace the content of e as seen by the caller with the newly created instance. In other cases such a result might be provided as a return value.
In general, the result of new T(), for some type T, is an instance of type T. You can thus work with the result of the expression new T() as you would a non-null variable of type T. In your particular case, you're assigning a value to a property on type T (specifically, the instance of that type thus created). (There is the special case where the constructor fails, but let's not go there for now; for simple types, that would pretty much mean that you are in such dire straits that your program is unlikely to be able to continue running in any case.)
What's important here is that if you don't assign the result of the expression new T() itself anywhere, the newly created instance is thrown away (technically, becomes inaccessible) once the statement completes. Then at some later point, the .NET garbage collector kicks in and actually reclaims the memory that was allocated. It isn't really any different from allocating a variable in one function, calling that function from another function and trying to access the variable thus allocated from the second function without doing anything to transfer the variable from the first function to the second, except here only one function is involved.
Doing something like your second line of code in the event handler would be rather unusual, but can in principle be valid if invoking the constructor has some side effect that you're looking to make use of, such as triggering lazy loading.
This code surely work just check it
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (PreClosingConfirmation() == System.Windows.Forms.DialogResult.Yes)
{
Dispose(true);
Application.Exit();
}
else
{
e.Cancel = true;
}
}
private DialogResult PreClosingConfirmation()
{
DialogResult res = System.Windows.Forms.MessageBox.Show(" Do you want to quit? ", "Quit...", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
return res;
}
Happy Coding
It's because the CancelEventArgs is an object reference passed to the event handler in your code. The behind the scenes code raises FormClosing with a CancelEventArgs object and all the event handlers receive that same object. Once all the handlers have had their turn, the behind the scenes code checks the CancelEventArgs object it sent to see if its Cancel property is set to true. If it is, it doesn't do anything, and the FormClose chain of events stops. If Cancel is false (CancelEventArgs default value), meaning it hasn't been set to Cancel the chain of events, the behind the scenes code proceeds along, and then raises the FormClosed event.
You can read more at Form.FormClosing Event on MSDN.
In Forms all the -ing events are typically followed by an -ed event. The -ing events usually have CancelEventArgs, which can have its Cancel property set to true to stop the -ed event from happening.
Is this a valid way to use a Lambda as an EventHandler? It seems to me that the handler has been correctly removed and that the garbage collector should clean this up. However, I haven't seen anyone else do it this way, so I thought I'd better double check.
Along the same lines, what's the best tool (preferably free) to use to test whether this is in fact being garbage collected?
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(10);
EventHandler callback = null;
callback = (s, e) =>
{
timer.Stop();
timer.Tick -= callback;
};
timer.Tick += callback;
timer.Start();
A DispatcherTimer is kept alive by the Dispatcher class, it keeps a List<DispatcherTimer> internally that stores a reference to any timer that's enabled. As soon as you Stop() the timer, the object gets removed from that list, making it eligible for garbage collection if you don't store any additional reference to it. Which you don't in this case, the timer reference is a local variable.
You cannot get a finalizer on the auto-generated class that implements the lambda. Next best thing is to simply run this code a billion times. If you don't get runaway member consumption and OOM then it obviously doesn't leak. You'll want to make the Interval shorter so it doesn't take until Christmas, 15 msec is good. Use a Timer to call the method so you don't get too many active timers at the same time and allow the dispatcher to do its job.
Yes, the callback will be eligible for garbage collection after the callback has executed once. This is a reasonable way of subscribing to an event in order to execute the handler just once.
It's tough to prove that the delegate will be garbage collected - or indeed that the object used to hold the captured variables callback and timer will be garbage collected, admittedly... you'd really want to put a finalizer there (which affects garbage collection itself, of course), but you can't as it's generated code.
I have the following code in a Windows Phone 7 Silverlight App of mine which is executed before navigating to another page.
Storyboard storyboard = Resources["TurnstileBackwardOut"] as Storyboard;
Storyboard.SetTarget(storyboard, LayoutRoot);
storyboard.Completed += delegate
{
storyboard.Stop();
Debug.WriteLine("LeavePageStoryboard.Completed");
NavigationService.Navigate(uri);
};
storyboard.Begin();
The Storyboard is in the resources and is reused quite often. As I understand it, whenever the code is executed, a new delegate is added to the Completed event. My question is: do I have to remove that delegate from the Completed event?
Otherwise after some time, there would be many delegates and some of them wouldn't even belong to the current page, because I use the storyboard on other pages as well.
You should be able to tell if this is a problem, because when you navigate you'll see lots of copies of "LeavePageStoryboard.Completed". Unless it's creating a new Storyboard each time, however, I suspect it is a problem. It's easy to fix though:
EventHandler completedHandler = null; // For definite assignment purposes
completedHandler = delegate
{
storyboard.Stop();
Debug.WriteLine("LeavePageStoryboard.Completed");
NavigationService.Navigate(uri);
storyboard.Completed -= completedHandler;
};
storyboard.Completed += completedHandler;
This is a memory leak, and a common one in C#. If you have a long lived object that gets reused often, it's common for event handlers to pile up on it.
There are a couple options:
1) Make your delegate not be anonymous. Create a method to hold its logic, and referenced delegates. Then remove this referenced delegate when you are done with storyboard.
2) Make storyboard not be long lived. One possibility is to make it a DataTemplate instead and instantiate new copies of it. Then you can attach event handlers to it all you want and once garbage collected, they will get garbage collected too.