net eventos evento ejemplo desuscribirse delegados crear c# design-patterns memory-leaks event-handling

c# - ejemplo - ¿Por qué y cómo evitar las fugas de memoria del controlador de eventos?



eventos c# (3)

Me acabo de dar cuenta, al leer algunas preguntas y respuestas en StackOverflow, que agregar manejadores de eventos usando += en C # (o supongo, otros lenguajes .net) puede causar fugas de memoria comunes ...

He usado manejadores de eventos como este muchas veces, y nunca me di cuenta de que pueden causar, o han causado, pérdidas de memoria en mis aplicaciones.

¿Cómo funciona esto? (Es decir, ¿por qué esto realmente causa una pérdida de memoria)?
Como puedo solucionar este problema ? ¿Está usando -= para el mismo controlador de eventos lo suficiente?
¿Hay patrones de diseño comunes o mejores prácticas para manejar situaciones como esta?
Ejemplo: ¿Cómo se supone que debo manejar una aplicación que tiene muchos subprocesos diferentes, usando muchos manejadores de eventos diferentes para generar varios eventos en la UI?

¿Hay formas buenas y simples de monitorear esto de manera eficiente en una gran aplicación ya construida?


La causa es simple de explicar: mientras se suscribe un controlador de eventos, el editor del evento contiene una referencia al suscriptor a través del delegado del controlador de eventos (suponiendo que el delegado es un método de instancia).

Si el editor vive más tiempo que el suscriptor, mantendrá al suscriptor con vida incluso cuando no haya otras referencias al suscriptor.

Si cancela su suscripción al evento con un controlador igual, entonces sí, eso eliminará el controlador y la posible fuga. Sin embargo, en mi experiencia, esto rara vez es realmente un problema, porque normalmente me parece que el editor y el suscriptor tienen una vida más o menos igual de todos modos.

Es una causa posible ... pero en mi experiencia es bastante exagerada. Su kilometraje puede variar, por supuesto ... solo debe tener cuidado.


Sí, -= es suficiente. Sin embargo, podría ser bastante difícil hacer un seguimiento de cada evento asignado, nunca. (para más detalles, vea la publicación de Jon). Con respecto al patrón de diseño, eche un vistazo al patrón de eventos débiles .


Un evento es realmente una lista vinculada de controladores de eventos

Cuando haces + = new EventHandler en el evento, realmente no importa si esta función en particular ha sido añadida como listener antes, se agregará una vez por + =.

Cuando se levanta el evento, vaya a través de la lista vinculada, elemento por elemento y llame a todos los métodos (controladores de eventos) agregados a esta lista, esta es la razón por la cual los manejadores de eventos aún se invocan incluso cuando las páginas ya no se ejecutan siempre que están vivos (enraizados), y estarán vivos mientras estén enganchados. Entonces se llamarán hasta que el controlador de eventos se desenganche con un - = new EventHandler.

Mira aquí

y MSDN AQUÍ