Garbage cleanup on c# events [duplicate] - c#

This question already has answers here:
Is it necessary to explicitly remove event handlers in C#
(2 answers)
Closed 5 years ago.
Let's say I have a c# class which can be subscribed to like so:
public class Emitter {
public delegate void EmitAction(Emitter emitter);
public event EmitAction OnEmitted;
public void DoEmit() {
if(OnEmitted != null)
OnEmitted(this);
}
}
...and another class that makes use of it:
public class EmissionUser {
public void SomeFunction() {
Emitter em = new Emitter();
em.OnEmitted += HandleIt;
em.DoEmit();
}
public void HandleIt(Emitter em) {
//I could just do em -= HandleIt, but is there any point?
}
}
I know that for code cleanliness and avoiding memory leaks, it's always good have one unsubscribe for every subscribe when using events. However in a case like this, the Emitter instance is created locally in SomeFunction(), and not held in memory for too long, so I'm guessing the event subscription is destroyed with the local instance.
Is it still a good idea to unsubscribe in the handler? If so why?

Well, em is a local instance and will get destroyed with the end of HandleIt. You can choose to leave it like that if you are not going to use it anywhere else.
But if you have the reference of it somewhere else, or going to create one in future, it would create problems. Also, finding root cause of bugs related to events is tricky.
I noticed that you are passing the emitter reference. Someone can again use the same reference to call different method or raise an event within handleIt.
So, I would suggest you to do it, just for the sake of future-proofing the code.

Yes you don't need to unsubscribe because as you said the em variable destroyed after the SomeFuction returned, and nobody else has reference to this object so the garbage collector can clean it up.

Related

Would subscribing to my own C# event create a memory leak?

If a base class publishes a C# event and a derived class subscribes to it -- i.e. subscribes to itself --. Will the event subscription prevent the object from being garbage collected? Or is the garbage collector smart enough to detect such circular reference situations.
At first glance, it seems like it should but I'm pretty sure I've seen control code that does this. This is such a fundamental question I can't believe I've never looked into it before.
Edit: For Juan R. I mean something like this. (Never compiled this code, just typed it off the top of my head so I might have typos/errors)
public class Base
{
public event EventHandler<double> ValueChanged;
}
public class Derived : Base
{
public Derived()
{
// Will this prevent my object from being collected?
ValueChanged += OnValueChanged;
}
private void OnValueChanged(object sender, double v)
{
}
}
An object subscribing to its own event will not cause a memory leak for the simple reason that the CLR GC is based on reachability, not reference counting. If the object is reachable from a GC root, then it was not eligible for GC anyway. And if it's not reachable, then a self-reference does not make it reachable. There is nothing special about events with regard to GCing circular references.

Negative Aspects/Bad Practice of Static Event in C#

I reuse the code below a lot when I create events that will be used in different areas of an application. I find it really helpful and it makes events very easy to follow in the code. Is there any reason why this could be a bad idea? This is a bit broad, but basically is there a reason not to do this?
Event classes:
public delegate void FocusEventHandler(object source, FocusEventArgs e);
class FocusEvent
{
public static event FocusEventHandler focusEvent;
public static void Focus(bool status)
{
focusEvent(null, new FocusEventArgs(status));
}
}
public class FocusEventArgs : EventArgs
{
public bool Focused { get; set; }
public FocusEventArgs(bool f)
{
Focused = f;
}
}
So to fire the event, all I need is:
FocusEvent.Focus(false);
Thanks guys. This helps a lot. I really need to read up on memory usage.
The single biggest problem with static events is that you need to be really careful about unsubscribing from them. With an instance event, if you don't unsubscribe then you might end up keeping part of a graph artificially alive until the object with the event is released and is unreachable (making all the subscribers unreachable) - however, a static event never becomes unreachable. This means that any subscribers that don't unsubscribe will never be unreachable, and will never be garbage collected.
A few years back, I worked on a large-scale Windows app that used static events. While investigating some memory usage issues, I discovered that no forms in the entire application were ever garbage collected. Pretty much every form subscribed to a static event, but never unsubscribed, causing them to stick around forever.
So yeah, the main reason not to do this is that you'll inevitably forget to unsubscribe from the event at some point, causing things to stick around for the lifetime of the application.

Destructor implemented via event

I have several objects in our framework, that by the requirement need to provide event ObjectTerminated. The user of the framework can subscribe to this event and clean-up some unmanaged stuff, that he is using. These objects are designed to exist the whole life time of the application, and I'm not controlling their life. You can think of them as an array of singletons.
I want to write code like this:
class SomeWorkflowControlObject
{
public event EventHandler<> ObjectTerminated;
~SomeWorkflowControlObject()
{
if (ObjectTerminated != null) ObjectTerminated(this, null);
}
}
I am not sure, am I allowed to do that. What could go possibly wrong with such solution?
Updated:
What about Process.GetCurrentProcess().Exited ? Can I use it in such manner?
You should not do this. Basically, destructors do not exist in C#. What you have written is a finalizer, and the only thing a finalizer should ever do is to free unmanaged resources.
You are not allowed to access any other managed object at all, since the garbage collector might already have removed it. I do not think your null check is a sufficient guard against this situation; that object reference might still point to your (event) delegate, even if it's already gone.
So in short, don't do this.
Alternatives:
Subscribe to the Application.ApplicationExit event if you have a Windows Forms application.
You might want to consider implementing the IDisposable interface instead and then do something like this:
public class SomethingVeryLongLived : IDisposable
{
…
}
…
public static void Main()
{
using (var sth = new SomethingVeryLongLived(…))
{
Application.Run(new SomeForm(…));
} // <-- at this point, foo.Dispose() is guaranteed to be called.
}
Take note that even in the case of using IDisposable, it's probably not a good idea / design to trigger an event inside the object that is getting disposed, since disposed objects should no longer be accessed.
For this very reason, I would recommend you do the following:
Use a try…finally block:
public static void Main()
{
var sth = new SomethingVeryLongLived(…);
try
{
Application.Run(new SomeForm(…));
}
finally
{
SomethingVeryLongLived.Terminate();
}
}
This would seem best to me because you are not abusing the IDisposable interface, and it's very clear what the code does... there's no hidden meaning.
I believe the design of that framework is inherently flawed. Let me explain:
1. [...] several objects in our framework, that by the requirement need to provide event ObjectTerminated.
This doesn't make sense. If an object has been terminated, as the event's name suggests, then I would assume that it is already gone and that I can no longer access it. This raises two questions:
How does something dead trigger an event? It's like a corpse talking to you from its grave, "I am dead." Do you really want this?
Why would anyone else be interested in reacting to such an event, if the event sender is no longer supposed to be there? What is there to clean up after the corpse has already been buried?
2. I'm not controlling their life.
Who is controlling their lifetime, then? Why isn't it their responsibility to do, or trigger, the necessary clean up work at the appropriate moment? Let me further elaborate on this very point:
3. [...] can subscribe to this event and clean-up some unmanaged stuff [...]
Where is this unmanaged stuff, and which object is responsible for handling it? If it is your own object, then why doesn't your object dispose of it — why do you instead want to trigger an event, so that someone else can dispose of the stuff? It's like me carrying out my neighbour's garbage, instead of him doing it himself. (I'm not talking about an old lady there.)
Your class would make much more sense if it looked like this:
class SomeWorkflowControlObject : IDisposable
{
// the following event doesn't make sense, sorry.
// public event EventHandler<> ObjectTerminated;
private IntPtr _handleToUnmanagedResource;
~SomeWorkflowControlObject()
{
Dispose(explicitly: false);
}
public void Dispose()
{
Dispose(explicitly: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool explicitly)
{
if (explicitly)
{
// free managed resources here; perhaps trigger an event 'Disposing'.
}
DisposeUnmanagedResource(_handleToUnmanagedResource);
}
}
That is, it is a wrapper around some unmanaged resource, for whose disposal it is responsible itself, and noone else. Thus, there is no longer a need to trigger an event, such that someone else can dispose the unmanaged resource, which should be hidden inside your object anyway.

WinForms: Should I always unregister event callbacks? [duplicate]

This question already has answers here:
Is it bad to not unregister event handlers?
(2 answers)
Closed 9 years ago.
I have code that looks like this:
class MyPresenter
{
public MyPresenter(IViewFactory viewFactory, ...)
{
_view = viewFactory.GetMyView();
_view.OkClicked += OnOkClicked;
_view.CancelClicked += OnCancelClicked;
...
}
public ShowView()
{
...
_view.ShowDialog();
}
}
Is it necessary to put a -= somewhere? And if so, does it make sense to put it in the finalizer?
it is important to unregister from an event when the lifetime of the subscribing object is assumed to be shorter than the lifetime of the object firing the event.
One good example is App.Idle. App lives throughout the lifetime of your Windows Forms App. If you register on this event, App now has a reference to said object, that is, if you don't unregister, your object assumes the same lifetime as App.
I would like to point you to my post on Windows.Forms "memory leaks". Note these do not prove there is anything wrong with the Garbage Collector, but there are corner cases, where unmanaged code isn't far away, or when you have lifetime issues surrounding events.

How to get rid of event handlers safely?

Let's say I have a class A which can fire an event called X. Now I have a class B and in a method I get an instance to A and bind the event to a handler in B:
public void BindEvent(A a)
{
a.X += AEventHandler;
}
I have three questions about this.
Is it true that when I now set the reference to the B instance to null, it won't be garbage collected since the garbage collector thinks it's still in use (thus keeping a useless and potentially interfering copy of B in memory).
What about when I have another object c (of class C) in which I have a reference to A called a ("this.a = new A()"). Then I call "b.BindEvent(this.a)", and in c I set the reference to a to null ("this.a = null"). Will this keep the copy of A in memory because it's referenced through the event in b?
If either or both are true of the above, how can I best circumvent these issues? If I have a whole list of event handlers (say 10 lines like "a.SomeEvent += SomeMethod") should I clean them all up again ("a.SomeEvent -= SomeMethod"). At which time or place in the code should I do these things?
Well it's gotten a bit fuzzy but I'm not sure how to explain in a better way. Please leave a comment if I need to explain something more detailed.
so: A is the publisher and B is the subscriber?
first bullet: if B is the instance with AEventHandler - then it is still in use, so no, it won't get collected unless the a instance is unreachable.
second bullet: huh? (will read again...) If the A and B instances are both unreachable, they will be garbage collected; the event doesn't matter. If A is reachable, then B will stay alive. However, the event subscription never keeps A alive; it is one way... A can keep B alive, but B doesn't keep A alive. Does that cover it?
third bullet: in most cases, the two things have similar life expentency, so it isn't an issue. It only becomes an issue if the thing publishing the event lives a lot longer than the things with the handlers. In which case, you simply need to religiously clean up after yourself - for example: a.X -= AEventHandler. In particular, static events are evil for this reason.
You should really unbind the event handler before destroying the class instance that it relates to. (Using your code as an exmaple.)
public void UnbindEvent(A a)
{
a.X -= AEventHandler;
}
I would also ask, why are you setting class variables to null?
Correct.
Correct.
Why would you want to circumvent this behaviour? It's how the GC is designed to work. If you need to do some clean up when each object is torn down, use the Dispose pattern.
Yes, event are references, if you don't unregister, the object implementing the event handler will not be garbage collected.
You can do this:
Remove all registered event, if A knows when they are not used anymore.
class A
{
// clearing all registrations
private void ClearEvents()
{
X = null;
}
}
Or you unregister in B, if B knows when it doesn't use it anymore. You need to keep a reference to a to be able to unregister.
You could also implement IDisposable.
class B : IDisposable
{
private A registeredToA;
public void BindEvent(A a)
{
registeredToA = a;
registeredToA.X += AEventHandler;
}
public void Dispose()
{
registeredToA.x -= AEventHandler;
}
}
This is a breaking change to your code, because B needs always to be disposed.

Categories