2008-08-19 9 views
19

Digamos que tenemos el siguiente método:¿El uso de lambdas como controladores de eventos causa una pérdida de memoria?

private MyObject foo = new MyObject(); 

// and later in the class 

public void PotentialMemoryLeaker(){ 
    int firedCount = 0; 
    foo.AnEvent += (o,e) => { firedCount++;Console.Write(firedCount);}; 
    foo.MethodThatFiresAnEvent(); 
} 

Si la clase con este método se crea una instancia y el método PotentialMemoryLeaker se llama varias veces, ¿tenemos pérdida de memoria?

¿Hay alguna manera de desenganchar ese controlador de eventos lambda después de que terminemos de llamar al MethodThatFiresAnEvent?

+0

Como se indica en las respuestas a continuación, no hay forma de desengancharlo sin conservar una referencia. Sin embargo, puede hacer que se desenganche: http://stackoverflow.com/questions/1747235/weak-event-handler-model-for-use-with-lambdas/1747236#1747236 – Benjol

Respuesta

16

Sí, guárdelo en una variable y desengánelo.

DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); }; 
foo.AnEvent += evt; 
foo.MethodThatFiresAnEvent(); 
foo.AnEvent -= evt; 

Y sí, si no lo hace, se le hay fugas de memoria, como podrá conectar un nuevo objeto delegado cada vez. También te darás cuenta de esto porque cada vez que llamas a este método, irá a la consola un número creciente de líneas (no solo un número creciente, sino que por una llamada a MethodThatFiresAnEvent arrojará cualquier cantidad de elementos, una vez por cada método anónimo conectado).

0

Sí, de la misma manera que los controladores de eventos normales pueden causar fugas. Debido a que el lambda es en realidad cambiado a:

someobject.SomeEvent +=() => ...; 
someobject.SomeEvent += delegate() { 
    ... 
}; 

// unhook 
Action del =() => ...; 
someobject.SomeEvent += del; 
someobject.SomeEvent -= del; 

Así que básicamente es sólo corta la mano por lo que hemos estado utilizando en todos estos años 2.0.

4

No solo perderá memoria, también recibirá su lambda llamada varias veces. Cada llamada de 'PotentialMemoryLeaker' agregará otra copia de la lambda a la lista de eventos, y se llamará a cada copia cuando se active 'AnEvent'.

1

Su ejemplo simplemente se compila en una clase interna privada con el nombre de compilador (con el campo firedCount y un método con nombre de compilador). Cada llamada a PotentialMemoryLeaker crea una nueva instancia de la clase de cierre a la que foo guarda una referencia por medio de un delegado al único método.

Si no hace referencia al objeto completo que posee PotentialMemoryLeaker, entonces todo será basura. De lo contrario, puede establecer foo en nulo o evento lista manejador de foo vacío escribiendo esto:

foreach (var handler in AnEvent.GetInvocationList()) AnEvent -= handler; 

Por supuesto, que había necesidad de acceso a los miembros privados del MiObjeto de clase.

3

bien que se puede extender lo que se ha hecho para hacer here delegados más seguro de usar (no hay pérdidas de memoria)

+1

el enlace está muerto – thumbmunkeys

Cuestiones relacionadas