¿Los controladores de eventos detienen la recolección de basura?

183

Si tengo el siguiente código:

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

¿Se recogerá pClass basura? ¿O pasará el rato disparando sus eventos cada vez que ocurran? ¿Tendré que hacer lo siguiente para permitir la recolección de basura?

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;
Mark Ingram
fuente
11
Voy a sugerir tentativamente a los lectores interesados ​​en esta pregunta que podría valer la pena familiarizarse con eventos livianos / patrones de eventos débiles, que NO impiden que ocurra la recolección de basura. Un buen arranque de SO para este tema es stackoverflow.com/questions/185931/…
fostandy
20
Nota para la posteridad: establecer la referencia en nulo simplemente retrasa al recolector de basura extendiendo en una línea el alcance de la referencia. .NET no es VB6.
John Saunders

Respuestas:

207

Para la pregunta específica "¿Se recolectará basura pClass?": La suscripción al evento no tiene ningún efecto en la recolección de pClass (como el editor).

Para GC en general (en particular, el objetivo): depende de si MyFunction es estático o está basado en instancias.

Un delegado (como una suscripción de evento) a un método de instancia incluye una referencia a la instancia. Entonces, sí, una suscripción a un evento evitará GC. Sin embargo, tan pronto como el objeto que publica el evento (pClass arriba) sea elegible para la recopilación, esto deja de ser un problema.

Tenga en cuenta que esto es unidireccional; es decir, si tenemos:

publisher.SomeEvent += target.SomeHandler;

entonces "publicador" mantendrá "objetivo" vivo, pero "objetivo" no mantendrá vivo "editor".

Entonces no: si pClass se va a recopilar de todos modos, no hay necesidad de cancelar la suscripción de los oyentes. Sin embargo, si pClass fue de larga duración (más larga que la instancia con MyFunction), entonces pClass podría mantener viva esa instancia, por lo que sería necesario darse de baja si desea que se recopile el objetivo.

Sin embargo, los eventos estáticos, por este motivo, son muy peligrosos cuando se usan con controladores basados ​​en instancias.

Marc Gravell
fuente
66
Bueno, si la pregunta es "¿se recolectará basura?", Entonces la respuesta "depende de si ..." en realidad no es correcta. No depende de nada, como Marc mismo señala más abajo.
Tor Haugen
Justo lo suficiente - - @Tor Voy a aclarar
Marc Gravell
Aunque un delegado de suscripción a un evento solo apunta en una dirección, un suscriptor que tenga la intención de darse de baja de un evento cuando haya terminado con él necesitará alguna forma de referencia para el editor. Podría ser una WeakReference, y en algunos casos, podría ser una buena idea, pero la mayoría de las veces será una buena idea.
supercat
Una gran respuesta porque también aborda la otra mitad de la pregunta (que no se hizo): el editor evitará que el suscriptor reciba GC.
Bob Sammers
Sí, y como dijo @BobSammers, realmente podría ser un problema si una instancia de corta vida, como un formulario / ventana, se suscribe a un servicio de larga duración como Singleton que proporciona datos, por ejemplo: Singleton luego mantiene una referencia y, por lo tanto, los objetos se guardan en la memoria incluso cuando pensamos que están descargados. Por lo tanto, tenga mucho cuidado al usar Eventos. Abusamos de los eventos para nuestro gran software, y es muy difícil de resolver después.
Elo
9

Sí, pClass será basura recolectada. La suscripción al evento no implica que exista ninguna referencia a pClass.

Y así no, no tendrá que separar el controlador para que se pueda recolectar basura de pClass.

Tor Haugen
fuente
8

En el momento en que ya no se hace referencia a un fragmento de memoria, se convierte en candidato para la recolección de basura. Cuando la instancia de su clase se sale del alcance, su programa ya no hace referencia a ella. Ya no se usa y, por lo tanto, se puede recoger de forma segura.

Si no está seguro de si se recolectará algo, hágase la siguiente pregunta: ¿existe alguna referencia al respecto? La instancia del objeto hace referencia a los controladores de eventos, no al revés.

lvaneenoo
fuente
0

pClassSe recogerá la basura. Sin embargo, si el fragmento de código anterior está dentro de otra clase, la instancia de esa clase podría no borrarse si no se establece pClassen null.

Arav
fuente