I gestori di eventi impediscono che si verifichi la garbage collection?


183

Se ho il seguente codice:

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

PClass sarà raccolta rifiuti? O resterà in giro ancora a sparare i suoi eventi ogni volta che si verificano? Dovrò fare quanto segue per consentire la raccolta dei rifiuti?

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

11
Suggerirò provvisoriamente ai lettori interessati a questa domanda che potrebbe valere la pena familiarizzare con eventi leggeri / modelli di eventi deboli, che NON impediscono la raccolta dei rifiuti. Un bootstrap buon SO a questo argomento è stackoverflow.com/questions/185931/...
fostandy

20
Nota per i posteri: impostare il riferimento su null semplicemente ritarda il garbage collector estendendo di una riga l'ambito del riferimento. .NET non è VB6.
John Saunders,

Risposte:


207

Per la domanda specifica "PClass sarà garbage collection": l'abbonamento all'evento non ha alcun effetto sulla raccolta di pClass (come l'editore).

Per GC in generale (in particolare il target): dipende dal fatto che MyFunction sia statica o basata su istanza.

Un delegato (come una sottoscrizione di evento) a un metodo di istanza include un riferimento all'istanza. Quindi sì, un abbonamento all'evento impedirà GC. Tuttavia, non appena l'oggetto che pubblica l'evento (pClass sopra) è idoneo per la raccolta, questo cessa di essere un problema.

Si noti che questo è a senso unico; cioè se abbiamo:

publisher.SomeEvent += target.SomeHandler;

quindi "editore" manterrà in vita "target", ma "target" non manterrà in vita "publisher".

Quindi no: se pClass verrà raccolto comunque, non è necessario annullare l'iscrizione agli ascoltatori. Tuttavia, se pClass era di lunga durata (più lungo dell'istanza con MyFunction), allora pClass poteva mantenere in vita quell'istanza, quindi sarebbe necessario annullare l'iscrizione se si desidera che il target venga raccolto.

Gli eventi statici, tuttavia, per questo motivo, sono molto pericolosi se utilizzati con gestori basati su istanza.


6
Bene, se la domanda è "la pClass sarà raccolta", allora la risposta "dipende se ..." non è effettivamente corretta. Non dipende da nulla, come lo stesso Marc nota più in basso.
Tor Haugen,

@Tor - abbastanza equo - io chiarire
Marc Gravell

Sebbene un delegato alla sottoscrizione di un evento punti solo in un modo, un abbonato che abbia intenzione di annullare l'iscrizione a un evento una volta terminato con esso avrà bisogno di qualche forma di riferimento per l'editore. Potrebbe essere una WeakReference, e in alcuni casi, potrebbe essere una buona idea, ma spesso sarà forte.
supercat

Un'ottima risposta perché affronta anche l'altra metà della domanda (che non è stata posta): l' editore impedirà all'abbonato di essere GC'd.
Bob Sammers,

Sì, e come ha detto @BobSammers, potrebbe davvero essere un problema se un'istanza di breve durata, come un modulo / finestra, si iscrive a un servizio di lunga durata come un Singleton che fornisce dati ad esempio: Singleton mantiene quindi un riferimento e gli oggetti vengono quindi tenuti in memoria anche quando pensiamo che siano scaricati! Quindi sii molto cauto quando usi gli Eventi. Abbiamo abusato degli eventi per il nostro grande software ed è molto difficile da risolvere in seguito.
Elo,

9

Sì, pClass verrà raccolta in modo inutile. La sottoscrizione dell'evento non implica l'esistenza di alcun riferimento a pClass.

Un così no, non dovrai staccare il gestore per poter raccogliere spazzatura pClass.


8

Nel momento in cui un pezzo di memoria non viene più referenziato, diventa un candidato per la garbage collection. Quando l'istanza della classe non rientra nell'ambito di applicazione, non viene più indicata dal programma. Non viene più utilizzato e quindi può essere raccolto in modo sicuro.

Se non sei sicuro se qualcosa verrà raccolto, poniti la seguente domanda: esiste ancora un riferimento ad esso? I gestori di eventi sono referenziati dall'istanza dell'oggetto, non viceversa.


0

pClasssarà raccolta dei rifiuti. Tuttavia, se lo snippet di codice sopra si trova all'interno di un'altra classe, l'istanza di quella classe potrebbe non essere cancellata se non si imposta pClasssu null.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.