Asked  7 Months ago    Answers:  5   Viewed   33 times

If I have the following code:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;

Will pClass be garbage collected? Or will it hang around still firing its events whenever they occur? Will I need to do the following in order to allow garbage collection?

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;

 Answers

80

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.

Tuesday, June 1, 2021
 
HexaGridBrain
answered 7 Months ago
27

At first I thought this would be the way to go:

public class DetailViewModel : IDisposable
{
    public DetailViewModel(MyDetailModel detailModel)
    {
        // Retain the Detail Model
        this.model = detailModel;

        // Handle changes to the Model not coming from this ViewModel
        this.model.PropertyChanged += model_PropertyChanged;  // Potential leak?
    }

    public void Dispose()
    {
        this.model.PropertyChanged -= model_PropertyChanged;
    }
}

But then I found this beautiful nugget. So, there are at least two possible solutions: (a) sample implementing IDisposable, and (b) arguments against IDisposable. I'll leave the debate to you. ;)

You may also consider the WeakEvent Pattern among others ...

Thursday, August 12, 2021
 
Mashhadi
answered 4 Months ago
63

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.

Thursday, August 12, 2021
 
Eddas
answered 4 Months ago
21

this.$div2 is appended to this.$div1. If I call this.$div1.remove(); and later lose the reference of my SomeClass instance does the SomeClass instance gets garbage collected?

Yes, when all references to it are lost - also those through event handlers , - the instance can get garbage-collected.

And what about the HTML element this.$div2? this.$div2 would not be inside the DOM because it is appended to this.$div1.

It does not matter whether it is currently attached to the DOM. If some non-collectible object references $div1, it also could access its child node $div2 and that one's event handlers, so the instance referenced from the handler would not be collectible.

I ask this because the event handler in this.$div2 might keep a reference to the HTML element this.$div2 and also keeps a reference to the instance of SomeClass through the closure because of the variable "that".

That's a circular reference and should get handled well by the engines (when none of the objects inside the circle is referenced from outside it can get collected). However, (old?) Internet Explorers fail to do this when a DOM object is involved in the circle.

For that reason the .remove jQuery method (code) internally calls the (internal) cleanData method which detaches all event listeners.

So should I care about properly removing all events and HTML elements like this? Or simply removing the "root" element (this.$div1) solves the problem?

Yes, calling remove on a jQuery wrapper automatically removes all events (from all child elements) and DOM nodes.

Saturday, September 11, 2021
 
Luis González
answered 3 Months ago
44

A couple of things to try, as suggested here:

  • In the timer tick event handler, stop your timer before doing your tick event handling, and restart it before exiting the handler
  • Wrap your timer code in a try/catch block to see what's happening.
  • Read the Elapsed event of the System.Timers.Timer class is not raised in a Windows service bug description/fix and see if that helps you.

In summary:

protected virtual void TimerTick(object sender, EventArgs e)
{
    // stop your timer
    this.timer.Stop();

    try
    {
        // TODO: add event handler specifics
    }
    catch
    {
        // TODO: add some logging to help you see what's going on
    }        

    // restart your timer
    this.timer.Start();
}
Sunday, October 3, 2021
 
learningpython
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share