Do event handlers stop garbage collection from occurring?
For the specific question "Will pClass be garbage collected": the event subscription has no effect on the collection of pClass (as the publisher).
For GC in general (in particular, the target): it depends whether MyFunction is static or instance-based.
A delegate (such as an event subscription) to an instance method includes a reference to the instance. So yes, an event subscription will prevent GC. However, as soon as the object publishing the event (pClass above) is eligible for collection, this ceases to be a problem.
Note that this is one-way; i.e. if we have:
publisher.SomeEvent += target.SomeHandler;
then "publisher" will keep "target" alive, but "target" will not keep "publisher" alive.
So no: if pClass is going to be collected anyway, there is no need to unsubscribe the listeners. However, if pClass was long-lived (longer than the instance with MyFunction), then pClass could keep that instance alive, so it would be necessary to unsubscribe if you want the target to be collected.
Static events, however, for this reason, are very dangerous when used with instance-based handlers.
Why event handlers prevent garbage collector from occurring
You are mis-identifying what is really going on, a very common trap in C#. You'll need to run the Release build of your test program and run it without the debugger (press Ctrl+F5). The way it will run on your user's machine. And now notice that it completely doesn't matter anymore whether or not you subscribe the event, you will always get 10.
The issue is that, when you use a debugger, the publisher object doesn't get collected. I explained the reason for that in detail in this answer.
Expanding a bit on that, you have circular references here. The Subscriber objects reference the Publisher object. And the Publisher object has references to the Subscriber objects. Circular references are not sufficient to keep objects alive. And thank goodness for that, garbage collection would not be very effective if that was the case. The publisher object must be referenced elsewhere to stay alive, the local variable isn't good enough.
How to keep event subscriptions from blocking garbage collection
You should look at the Weak Event Patterns :
https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/weak-event-patterns
Do event handlers stop garbage collection if the hanlder is in a seperate assembly?
It is the same regardless of which assembly the classes originate from.
Garbage collector and event handlers
It wouldn't cause a leak - the GC can handle circular references with no problems.
However, it would mean that the publisher would effectively have a reference to the subscriber, so the subscriber couldn't be garbage collected until either the publisher is eligible for GC, or it unsubscribes from the event.
Event handler affects in garbage collection in CLR
In summary
It is not the event itself that is causing this, but rather referencing an instance member of class A from a long running thread using a closure.
The event itself is not the issue, or is it?
This code a1.timeChange += A1_timeChange;
causes a delegate inside class A that implements the event public event EventHandler timeChange
to reference A1_timeChange
inside class B.
So, the reference is the other way around
In your scenario, if you got rid of all references to class B, but did not unsubscribe from the event, then the event handler in A that points to a handler method in B could keep class B reachable, and therefore not GC'ed
What is really happening
Your class A is accessible from one of the GC roots (specifically, actively running threads), it's still reachable and therefore, not collected - read more
You have spawned an eternally running task (well it will stop when the app closes / foreground thread terminates) with this code
Task.Factory.StartNew(() => {
while (true)
{
timeChange(DateTime.Now, null);
System.Threading.Thread.Sleep(3000);
}
The thing is, that you're using a lambda that closes over the timeChange
event, and that makes a compiler to generate a class that simply references class A
One more thing, just by having a descructor (which is compiled to a finalizer) you prolong the lifetime of your object by one GC collection - on the first GC, your object will be marked as unreachable, and will be put onto finalization queue. And on the next GC, the finalizer will actually run - read more
Will an anonymous-delegate event listener prevent garbage collection?
The following test suggests that, no, the scenario does not result in a memory leak.
public partial class LeakTest : UserControl
{
public ICommand PopupCommand { get; private set; }
public LeakTest()
{
InitializeComponent();
PopupCommand = new DelegateCommand(arg =>
{
var child = new ChildWindow();
child.Closed += (sender, args) =>
{
System.Diagnostics.Debug.WriteLine("Closed window");
};
// when the window has loaded, close it and re-trigger the command
child.Loaded += (sender, args) =>
{
child.Close();
PopupCommand.Execute(null);
};
child.Show();
});
}
}
The reason is suggested in the answer to the (Winforms) post linked to by Jwosty:
In your example, the publisher only exists within the scope of your private method, so both the dialog and the handler will be garbage collected at some point after the method returns.
In other words, the memory-leak concern is really the other way around -- the event publisher (the ChildWindow
control) holds a reference to the subscriber (the DelegateCommand
), but not the other way around. So, once the ChildWindow
is closed, the garbage collector will free its memory.
Can event listener of WeakEvent be deleted by garbage collection any time?
Yes, if the WeakReference
is the only thing which holds a reference to ListenerObject
, then ListenerObject
can be GC'd at any point.
You would use a pattern like this if your EventWrapper
class is not the only thing which has a reference to ListenerObject
, but your EventWrapper
doesn't know when that other thing is going to release its reference to ListenerObject
.
For example, ListenerObject
might be a UI control which appears on a screen, and the EventWrapper
might be owned by a singleton service. The UI control will stay alive as long as that screen is shown, but will be released when the user changes the screen. The service might not know when that happens. Using a weak event pattern means that you don't accidentally end up with a memory leak in this case.
Note, if you do want to implement the weak event pattern, use a WeakEventManager
as detailed in this article.
Related Topics
Set Object Property Using Reflection
Use of Finalize/Dispose Method in C#
Typenamehandling Caution in Newtonsoft Json
Automating the Invokerequired Code Pattern
How to Convert a Column Number (E.G. 127) into an Excel Column (E.G. Aa)
How to Recursively List All the Files in a Directory in C#
Getting Attributes of Enum'S Value
Public Fields Versus Automatic Properties
Evaluating String "3*(4+2)" Yield Int 18
What Is the Best Workaround For the Wcf Client 'Using' Block Issue
Easiest Way to Read from and Write to Files
What's a "Static Method" in C#