Mi sono appena reso conto, leggendo alcune domande e risposte su StackOverflow, che l’aggiunta di gestori di eventi usando +=
in C # (o, credo, altri linguaggi .net) può causare perdite di memoria comuni …
Ho usato gestori di eventi come questo in passato molte volte, e non ho mai realizzato che possano causare, o causare, perdite di memoria nelle mie applicazioni.
Come funziona (cosa significa, perché ciò causa effettivamente una perdita di memoria)?
Come posso risolvere questo problema? Sta usando -=
allo stesso gestore di eventi abbastanza?
Esistono modelli di progettazione comuni o best practice per gestire situazioni come questa?
Esempio: come posso gestire un’applicazione con molti thread diversi, utilizzando molti gestori di eventi diversi per generare diversi eventi nell’interfaccia utente?
Ci sono dei modi buoni e semplici per monitorare questo in modo efficiente in una grande applicazione già costruita?
La causa è semplice da spiegare: mentre un gestore di eventi è sottoscritto, l’ editore dell’evento detiene un riferimento al sottoscrittore tramite il delegato del gestore di eventi (supponendo che il delegato sia un metodo di istanza).
Se l’editore vive più a lungo dell’abbonato, manterrà vivo l’abbonato anche quando non ci sono altri riferimenti al sottoscrittore.
Se annulli l’iscrizione all’evento con un gestore uguale, allora sì, questo rimuoverà il gestore e la ansible perdita. Tuttavia, nella mia esperienza questo è raramente un problema – perché in genere trovo che l’editore e il sottoscrittore abbiano comunque uguali vite uguali.
È una ansible causa … ma nella mia esperienza è piuttosto sopraffatto. Il tuo chilometraggio può variare, ovviamente … devi solo stare attento.
Sì, -=
è sufficiente, Tuttavia, potrebbe essere abbastanza difficile tenere traccia di ogni evento assegnato, sempre. (per i dettagli, guarda il post di Jon). Per quanto riguarda il modello di progettazione, dai un’occhiata al modello di evento debole .
Un evento è in realtà un elenco collegato di gestori di eventi
Quando fai + = new EventHandler sull’evento, non importa se questa particolare funzione è stata aggiunta come listener in precedenza, verrà aggiunta una volta per + =.
Quando l’evento viene sollevato, passa attraverso l’elenco collegato, articolo per elemento e chiama tutti i metodi (gestori di eventi) aggiunti a questo elenco, questo è il motivo per cui i gestori di eventi vengono ancora chiamati anche quando le pagine non sono più in esecuzione purché sono vivi (radicati) e saranno vivi finchè saranno collegati. Così verranno chiamati fino a quando l’eventhandler non sarà sganciato con un – = nuovo EventHandler.
Vedere qui
e MSDN QUI