11 Stimmen

Muss ich mich von anonymen Ereignishandlern lokaler Variablen abmelden?

Wenn ich einen Code habe, der etwa so aussieht:

public void Foo()
{
    Bar bar = new Bar();

    bar.SomeEvent += (sender, e) =>
    {
        //Do something here
    };

    bar.DoSomeOtherThingAndRaiseSomeEvent();
}

Will bar gesammelt werden, wenn die Methode den Anwendungsbereich verlässt, oder muss ich das Ereignis manuell abbestellen, um ein Speicherleck aufgrund eines Verweises auf SomeEvent ?

18voto

Adam Robinson Punkte 176996

Ihre Situation ist in Ordnung; das Ereignis Teilnehmer wird nicht verhindern, dass die Herausgeber aber auch das Gegenteil kann der Fall sein.

Zum Beispiel,

class Foo
{
    public event EventHandler FooEvent;

    void LeakMemory()
    {
        Bar bar = new Bar();

        bar.AttachEvent(this);
    }
}

class Bar
{
    void AttachEvent(Foo foo)
    {
        foo.FooEvent += (sender, e) => { };
    }
}

In diesem Fall wird die Instanz von Bar erstellt innerhalb LeakMemory kann nicht eingezogen werden, bis entweder

  • Die anonyme Methode, die durch das Lambda dargestellt wird, wird aus FooEvent die Liste der Aufrufe
  • Die Instanz von Foo, an die sie angehängt ist, kann gesammelt werden

Der Grund dafür ist, dass das Ereignis (das nur ein syntaktischer Zucker für eine gewöhnliche delegate Instanz) hält eine Liste von Delegierten, die aufgerufen werden, wenn sie aufgerufen wird, und jeder dieser Delegierten hat wiederum einen Verweis auf das Objekt, an das er angehängt ist (in diesem Fall die Instanz von Bar ).

Beachten Sie, dass wir hier nur über die Sammlung Förderungswürdigkeit hier. Nur weil es förderfähig ist, heißt das noch lange nicht, dass wenn (oder sogar, wirklich, wenn ) es wird gesammelt, nur dass es kann sein.

1voto

Jon Skeet Punkte 1325502

Nun, das Ziel bar verweist, wird nicht automatisch sofort gelöscht... es ist nur so, dass die bar Variable wird nicht verhindern. vor dem Garbage Collecting bewahrt werden.

Der Ereignishandler wird nicht verhindern, dass die Instanz von Bar Das "normale" Problem besteht darin, dass ein Event-Handler die Teilnehmer eines Ereignisses vor dem Garbage Collecting (wenn es eine Instanzmethode verwendet oder "this" in einer anonymen Funktion erfasst). Es hat normalerweise keinen Einfluss auf die Herausgeber die in der Müllabfuhr landen. Denken Sie nur daran, dass der Herausgeber einen Verweis auf alle Abonnenten behalten muss - der Abonnent muss sich nicht daran erinnern, was er abonniert hat, es sei denn, er will sich ausdrücklich abmelden oder später ein anderes Mitglied verwenden.

Angenommen, nichts anderes hält Ihre Instanz von Bar lebend, sollte Ihr Code in Ordnung sein.

1voto

KeithS Punkte 67713

Die obigen Antworten sind korrekt; ich wollte nur eine Anmerkung machen. Anonyme Delegierte, die als Handler verwendet werden, können nur abbestellt werden, wenn Sie einen anderen Verweis auf den Delegaten/Lambda beibehalten. Das liegt daran, dass Lambdas "Funktionsliterale" sind, ähnlich wie Stringliterale, aber im Gegensatz zu Strings werden sie bei der Bestimmung der Gleichheit NICHT semantisch verglichen:

public event EventHandler MyEvent;

...

//adds a reference to this named method in the context of the current instance
MyEvent += Foo;

//Adds a reference to this anonymous function literal to MyEvent
MyEvent += (s,e) => Bar();

...

//The named method of the current instance will be the same reference
//as the named method.
MyEvent -= Foo;

//HOWEVER, even though this lambda is semantically equal to the anonymous handler, 
//it is a different function literal and therefore a different reference,
//which will not match the anonymous handler.
MyEvent -= (s,e) => Bar();

var hasNoHandlers = MyEvent == null; //false

//To successfully unsubscribe a lambda, you have to keep a reference handy:

EventHandler myHandler = (s,e) => Bar();

MyEvent += myHandler;

...

//the variable holds the same reference we added to the event earlier,
//so THIS call will remove the handler.
MyEvent -= myHandler;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X