Se il mio software ha due istanze di oggetto, una delle quali è sottoscritta agli eventi dell'altra. Devo cancellarli prima che siano orfani perché possano essere ripuliti dal garbage collector? O c'è qualche altra ragione per cui dovrei cancellare le relazioni dell'evento? Cosa succede se l'oggetto sottoscritto è orfano ma l'utente non lo è, o viceversa?Devo rimuovere le sottoscrizioni agli eventi dagli oggetti prima che siano orfani?
risposta
Sì, sì. Gli editori dell'evento sono in possesso di riferimenti agli oggetti e impedirebbero loro di raccogliere dati inutili.
Diamo un'occhiata a un esempio per vedere cosa succede. Abbiamo due classi; si espone un evento, l'altro si consuma:
class ClassA
{
public event EventHandler Test;
~ClassA()
{
Console.WriteLine("A being collected");
}
}
class ClassB
{
public ClassB(ClassA instance)
{
instance.Test += new EventHandler(instance_Test);
}
~ClassB()
{
Console.WriteLine("B being collected");
}
void instance_Test(object sender, EventArgs e)
{
// this space is intentionally left blank
}
}
noti come ClassB non memorizza un riferimento all'istanza ClassA; semplicemente collega un gestore di eventi.
Ora, vediamo come vengono raccolti gli oggetti. Scenario 1:
ClassB temp = new ClassB(new ClassA());
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();
Creiamo un'istanza di ClassB e ne manteniamo un riferimento tramite la variabile temp. Viene passata una nuova istanza di ClassA, in cui non viene memorizzato alcun riferimento a esso in alcun modo, quindi esce dall'ambito immediatamente dopo l'esecuzione del costruttore ClassB. Abbiamo il garbage collector eseguito una volta quando ClassA è andato fuori portata, e una volta quando ClassB è andato fuori ambito. L'output:
Collect 1
A being collected
Collect 2
B being collected
Scenario 2:
ClassA temp = new ClassA();
ClassB temp2 = new ClassB(temp);
temp2 = null;
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();
viene creata una nuova istanza di ClasseA e un riferimento è memorizzato nella variabile temporanea. Quindi viene creata una nuova istanza di ClassB, ottenendo l'istanza ClassA in temp passata ad esso e memorizziamo un riferimento ad esso in temp2. Quindi impostiamo temp2 su null, rendendo l'istanza ClassB fuori dal campo di applicazione. Come prima, abbiamo il garbage collector eseguito dopo ogni istanza è andato fuori portata. L'output:
Collect 1
Collect 2
B being collected
A being collected
Quindi, per concludere; se l'istanza che espone un evento esce dall'ambito, diventa disponibile per la garbage collection, indipendentemente dal fatto che ci siano o meno gestori di eventi collegati. Se un'istanza che ha un gestore eventi collegato a un evento in un'altra istanza, non sarà disponibile per la garbage collection finché il gestore eventi non viene rimosso o l'istanza a cui è collegato il gestore eventi diventa disponibile per la garbage collection.
Hai solo bisogno di sganciare gli eventi se l'oggetto esponendo eventi è longevo, ma l'oggetto aggancio l'evento sarebbe altrimenti essere di breve durata (e ottenere garbage collection abbastanza rapidamente).
In questo caso, non riuscire a sganciare causerà una perdita di memoria, perché il tuo oggetto di breve durata non sarà in grado di essere sottoposto a GC, perché l'evento nell'oggetto a lunga durata rimane su un delegato, che contiene un riferimento all'oggetto di breve durata. Poiché l'oggetto di breve durata è ancora referenziato da quel delegato, non può ottenere la raccolta di dati inutili.
Gli eventi statici sono longevi per definizione: vivono fino all'uscita dal programma. Se si aggancia un evento statico, è assolutamente necessario sganciarlo quando hai finito.
Se entrambi gli oggetti stanno per essere orfani, lo sganciamento non è necessario.
L'iscrizione a un evento comporta un forte riferimento al sottoscrittore. Questo perché, sotto le copertine, gli eventi sono delegati e i delegati ai metodi di istanza sono una combinazione del riferimento all'oggetto e del metodo effettivo. Se non annulli l'iscrizione, il publisher continuerà a mantenere i riferimenti e gli oggetti sottoscrittori non diventeranno mai orfani (e GC) finché il publisher sarà vivo.
Il contrario non è vero, ad esempio l'oggetto sottoscritto non ha alcun riferimento all'editore.
- 1. Devo rimuovere questo tipo di gestore eventi?
- 2. Rimuovere i dati dagli oggetti nidificati senza mutare
- 3. Devo rimuovere un gestore di eventi?
- 4. ReactiveUI perde le sottoscrizioni?
- 5. Cosa devo fare prima di eliminare elementi in un vettore di puntatori agli oggetti allocati dinamicamente?
- 6. Assicurarsi che gli oggetti siano chiusi se viene generata un'eccezione
- 7. Perché NHibernate non elimina prima gli orfani?
- 8. Ascolta le modifiche agli eventi iCal dal server
- 9. Programmazione orientata agli oggetti
- 10. Le sottoscrizioni di gruppo vengono gestite automaticamente su Riconnetti?
- 11. Scala.js: Utilizzo addEventListener di aggiungere eventi agli oggetti
- 12. Devo removeTarget prima addTarget
- 13. Il garbage collector cancella gli oggetti sottoscritti agli eventi?
- 14. È necessario verificare che gli oggetti siano effettivamente allocati?
- 15. Aggiornamento dell'interfaccia utente dagli eventi che utilizzano asyc attendere
- 16. Come associare le modifiche agli oggetti Realm?
- 17. Python: rimozione degli spazi dagli oggetti lista
- 18. xmlNodo agli oggetti
- 19. Devo rimuovere e.printStackTrace() dal mio codice prima di pubblicare
- 20. GHCJS-DOM guida agli eventi
- 21. Devo scrivere test prima che vengano compilati?
- 22. Reactjs - Orientato agli oggetti?
- 23. Devo rimuovere TestFlight prima di inviarlo ad App Store?
- 24. Devo conservare o autorelease prima di restituire oggetti?
- 25. È possibile iscriversi alle sottoscrizioni di eventi in C#?
- 26. Le chiamate sovrascritte del costruttore genitore funzionano prima che tutti i costruttori figli siano finiti
- 27. Devo mantenere/rimuovere esempi di allenamento identici che rappresentano oggetti diversi?
- 28. Filiali orfani in TFS
- 29. Come posso testare le sottoscrizioni di aggregatori di eventi Prism, su UIThread?
- 30. Problema di progettazione orientata agli oggetti