¿Por qué el GC no puede recopilar la instancia vinculada a un evento?

Esta pregunta basada en esta pregunta: Cómo disponer de la variable local que contiene el evento

Alguien dijo: un controlador de eventos para una instancia, ¿se agregará el recuento de referencia de la instancia? ¿Por qué?

preguntado el 12 de junio de 12 a las 13:06

mira este hilo, te puede ser de ayuda stackoverflow.com/questions/506092/… -

Esa respuesta es incorrecta, básicamente: el que responde tiene sus conceptos al revés. He agregado un comentario a la respuesta. -

3 Respuestas

Su pregunta vinculada, como dice Jon Skeet, lo tiene al revés. Lo único que se mantiene watcher Alive es quizás su propia implementación interna donde puede (o no) registrar un evento con un objeto de nivel inferior que es responsable de retroalimentar los "ticks". -pero esto es solo una conjetura.

Al hacer clic en el botón dos veces obtendrá dos separado watcher casos, cada uno con una suscriptor de la PositionChanged evento (que resulta ser el mismo método en la misma instancia).

Es importante destacar que no es el PositionChanged suscriptor que se mantiene watcher vivo después de que el método se cierra, es otra cosa (sospecho que está enterrado dentro del GeoCoordinateWatcher implementación). Cuando el método sale, una referencia a una instancia particular de watcher is correctamente salió de la pila, pero debido a una alternativa, referencia que se lleva a cabo en watcher el recuento de referencia efectivo a los ojos del CLR sigue siendo mayor que cero; por lo tanto, no elegible para la recolección de basura.

Debido a esto, continuará disparando el PositionChanged evento. Como nada en el evento impide que el observador continúe, supongo que puede tener una pérdida de memoria porque cada clic en el botón creará y dejar con vida una instancia de observador.

O necesita almacenar y usar solo uno GeoCoordinateWatcher clase, o cierre / elimine / detenga cada vez que maneje el evento.


La consideración habitual con los eventos y las suscripciones es tener en cuenta los objetos de corta duración que se suscriben a los objetos de larga duración.

Los delegados tienen referencias a un método en particular en una instancia particular de una clase (o solo al tipo en sí mismo si fuera un método estático). La suscripción a un evento hace que el editor del evento retenga inadvertidamente una referencia a la instancia del suscriptor a través del delegado de la suscripción.

Obviamente, si registra un método estático como controlador de eventos, no obtendrá este recuento de referencias porque no hay ninguna instancia.

Puede ocurrir una fuga de memoria si el suscriptor es de corta duración y el editor de eventos es de larga duración, si no cancela la suscripción. Supongamos que al suscriptor le gustaría ser elegible para GC, porque tiene una suscripción activa para un evento en algún lugar y que el objeto sigue vivo, no puede ser elegible hasta que se elimine de esa lista de suscripción.

Respondido el 12 de junio de 12 a las 14:06

Eso es todo correcto, pero no es lo que preguntaba el OP: la respuesta a la que se hace referencia habla sobre el controlador de eventos que mantiene el editor vivo, lo cual es incorrecto. - jon skeet

@JonSkeet Bastante justo, atrapado con las manos en la masa sin realmente leer la pregunta vinculada. Eliminaré esto. - adam houldsworth

Tacha eso, leí la otra pregunta y modifiqué mi respuesta. - adam houldsworth

@AdamHouldsworth ¡Muchas gracias! Descompilé la clase GeoCoordinateWatcher y descubrí que el método Start() se agregará a ThreadPool, ¡así que el GC no lo recopilará! - Dozer

@Dozer No hay problema, me alegro de que hayas encontrado la causa. - adam houldsworth

Porque llamando GeoCoordinateWatcher.Inicio empiezas una nueva tarea. Incluso si se declara en tu codificar como un local variable, continuará en vivo después de la salida del alcance de la función.

Puedes pensar en esto, como si comenzaras una tercera parte. process de la función. El alcance de la función se ha ido, pero el proceso sigue vivo.

En el enlace provisto, si hace clic en el botón dos veces, esto conducirá a 2 instancias diferentes de la GeoCoordinateWatcher ser manejado por el mismo controlador de eventos. Entonces ese controlador de eventos se invocará dos veces desde 2 instancias diferentes de GeoCoordinateWatcher.

Respondido el 12 de junio de 12 a las 13:06

Cuando crea un objeto delegado, contiene el Method y Target propiedades. los Target propiedad apunta al objeto cuyo contexto el Target se llamará al método (primer parámetro, también conocido como this).

En determinadas circunstancias, la referencia al objeto delegado estará activa, impidiendo así que el Target instancia de ser GCed. Por lo general, sucede cuando tiene una aplicación basada en complementos/complementos, o algún otro tipo de situación de enlace tardío, o está haciendo mucho trabajo con delegados y los objetos delegados están almacenados en alguna colección, o tiene un campo estático con un objeto delegado (ya que los campos estáticos nunca se recopilan), etc.

Tenga en cuenta que la recolección de basura no es susceptible al problema de "referencia circular"; para que un objeto se considere "útil", debe ser accesible desde la pila actual.

Respondido el 12 de junio de 12 a las 13:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.