Pregunta

He creado un "adjunto comportamiento" en mi aplicación de WPF que me permite manejar el Entrar keypress y pasar al siguiente control.Yo lo llamo EnterKeyTraversal.IsEnabled, y usted puede ver el código en mi blog aquí.

Mi principal preocupación ahora es que puede haber una pérdida de memoria, ya que yo soy el manejo de la PreviewKeyDown evento en UIElements y nunca explícitamente se "desenganche" del evento.

¿Cuál es el mejor método para evitar esta fuga (si las hay)?Debo mantener una lista de los elementos que estoy dirigiendo, y desenganchar el PreviewKeyDown evento en la Aplicación.Evento de salida?Alguien ha tenido éxito con sus correspondientes comportamientos en sus propias aplicaciones de WPF y venir para arriba con un elegante gestión de memoria solución?

¿Fue útil?

Solución

No estoy de acuerdo DannySmurf

Algunos de WPF objetos de diseño pueden obstruir su memoria y hacer que su aplicación muy lento cuando no están en el recolector de basura.Así que me parece la elección de las palabras para ser correcta, de una pérdida de memoria de los objetos que ya no usa.Usted espera que los elementos de la recolección, pero no es así, porque hay una referencia en algún lugar (en este caso en el de un controlador de eventos).

Ahora para una respuesta real :)

Te aconsejo que leas este WPF Rendimiento artículo de MSDN

No Quitar los Controladores de Eventos en los Objetos puede Conservar los Objetos Vivos

El delegado que un objeto pasa a su caso es, efectivamente, una referencia a ese objeto.Por lo tanto, evento los controladores pueden conservar los objetos con vida por más tiempo de lo esperado.Al realizar limpio de un objeto que se ha registrado en las escuchar a un objeto de evento, es esencial para eliminar el delegado antes de soltar el objeto.Mantener los objetos innecesarios vivo aumenta la aplicación del uso de la memoria.Este es especialmente cierto cuando el objeto es la de la raíz de un árbol lógico o un visual árbol.

Ellos aconsejan a mirar a la Débil Evento patrón

Otra solución sería quitar los controladores de eventos cuando se hace con un objeto.Pero yo sé que con las Propiedades asociadas que punto puede no ser siempre, claro..

Espero que esto ayude!

Otros consejos

El debate filosófico a un lado, mirando a la OP entrada en el blog, no veo ninguna fuga de aquí:

ue.PreviewKeyDown += ue_PreviewKeyDown;

Un duro referencia a ue_PreviewKeyDown se almacena en ue.PreviewKeyDown.

ue_PreviewKeyDown es un STATIC método y no puede ser GCed.

No hay referencia a ue se almacenan, por lo que nada impide que se GCed.

Así que...Donde es la fuga?

Sí sé que en los viejos días de pérdidas de Memoria son totalmente diferentes sujetos.Pero con el código administrado, un nuevo significado al término de Pérdida de Memoria podría ser más apropiado...

Microsoft reconoce a una fuga de memoria:

¿Por qué Implementar el WeakEvent Patrón?

La escucha de eventos que pueden conducir a pérdidas de memoria.La típica técnica de para escuchar un evento es el uso de el lenguaje de sintaxis específica que se conecta a un controlador a un evento en un fuente.Por ejemplo, en C#, que la sintaxis es:fuente.SomeEvent += new SomeEventHandler(MyEventHandler).

Esta técnica crea un fuerte la referencia de la fuente de evento para el detector de eventos.Normalmente, adjuntando un controlador de eventos para un oyente causas el detector tiene un objeto toda la vida que influenciado por el objeto vida útil de la fuente (a menos que el controlador de eventos se ha eliminado).Pero en ciertas circunstancias, usted podría desea que el tiempo de vida del objeto de la escucha a ser controlado por el otros factores, tales como si es actualmente pertenece al árbol visual de la aplicación, y no por el vida útil de la fuente.Siempre que el objeto de origen de toda la vida se extiende más allá de el tiempo de vida del objeto de la escucha, el evento normal conduce a un patrón de pérdida de memoria:el oyente se mantiene vivo más de lo que se pretendía.

Hacemos uso de WPF para un cliente de la aplicación con gran ToolWindows que se pueden arrastrar a caer, todos los ingenioso cosas, y todo ello compatible con un XBAP..Pero hemos tenido el mismo problema con algunos ToolWindows que no estaban en el recolector de basura..Esto era debido al hecho de que todavía era dependiente de detectores de eventos..Ahora bien, esto podría no ser un problema cuando se cierra la ventana y cerrar la aplicación.Pero si usted está creando muy grande ToolWindows con un montón de comandos, y todos estos comandos se re-evaluó una y otra vez, y la gente tiene que usar su aplicación durante todo el día..Que puedo decir..realmente se obstruye su memoria y tiempo de respuesta de la aplicación..

También, me resulta mucho más fácil de explicar a mi manager que tenemos una pérdida de memoria, de explicándole que algunos objetos no están en el recolector de basura debido a algunos acontecimientos que necesita limpieza ;)

@Nick Sí, la cosa conectada con comportamientos es que, por definición, no están en el mismo objeto como de los elementos cuyos eventos en que usted maneja.

Creo que la respuesta radica en el uso de WeakReference de alguna manera, pero yo no he visto ninguna simples ejemplos de código para que me lo explique.:)

Ha pesar de la implementación de la "Débil Evento Patrón" en lugar de regular los eventos?

  1. Débil Evento Patrón en WPF
  2. Débil Evento Patrones (MSDN)

Para explicar mi comentario sobre John Fenton post aquí está mi respuesta.Vamos a ver el siguiente ejemplo:

class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        var b = new B();

        a.Clicked += b.HandleClicked;
        //a.Clicked += B.StaticHandleClicked;
        //A.StaticClicked += b.HandleClicked;

        var weakA = new WeakReference(a);
        var weakB = new WeakReference(b);

        a = null;
        //b = null;

        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        Console.WriteLine("a is alive: " + weakA.IsAlive);
        Console.WriteLine("b is alive: " + weakB.IsAlive);
        Console.ReadKey();
    }


}

class A
{
    public event EventHandler Clicked;
    public static event EventHandler StaticClicked;
}

class B
{
    public void HandleClicked(object sender, EventArgs e)
    {
    }

    public static void StaticHandleClicked(object sender, EventArgs e)
    {
    }
}

Si usted tiene

a.Clicked += b.HandleClicked;

y establecer sólo b a null ambas referencias weakA y weakB permanecer vivo!Si se configura un valor null b se mantiene vivo, pero no un (lo que demuestra que John Fenton es incorrecto afirmar que un duro de referencia se almacena en el evento de que el proveedor, en este caso).

Esto me llevó a la conclusión ERRÓNEA de que

a.Clicked += B.StaticHandleClicked;

podría dar lugar a una fuga porque a pesar de la instancia de un ser guardada por el controlador estático.Este no es el caso (prueba de mi programa).En el caso de la estática de controlador de eventos o acontecimientos de los que es la otra manera alrededor.Si usted escribe

A.StaticClicked += b.HandleClicked;

una referencia se mantendrá a b.

Asegúrese de evento de referencia a elementos en el objeto al que se hace referencia, como cuadros de texto en el formulario de control.O si que no puede ser prevenido.Crear un evento estático en un mundial de ayudante de clase y, a continuación, supervisar el mundial de ayudante de clase de eventos.Si estos dos pasos no se puede hacer trate de usar un WeakReference, que generalmente son perfectos para estas situaciones, pero ellos vienen con una sobrecarga.

Acabo de leer tu blog y creo que tienes un poco de engañosa consejos, Matt.Si hay un real memoria fuga aquí, entonces eso es un error en el .NET Framework, y no algo que se puede corrige necesariamente en el código.

Lo que yo creo que usted (y el cartel en tu blog) son en realidad hablando aquí no es en realidad una fuga, sino más bien un continuo consumo de memoria.Que no es lo mismo.Para ser claros, la memoria perdida de la memoria es reservada por un programa, entonces abandonado (es decir, que es un puntero a la izquierda colgando), y que posteriormente no pueden ser liberados.Debido a que la memoria se gestiona .NETO, esto es teóricamente imposible.Es posible, sin embargo, para que un programa de reserva de una creciente cantidad de memoria sin permitir que las referencias a ir fuera de alcance (y a ser elegible para la recolección de basura);sin embargo, que la memoria no se pierde.La GC se vuelve al sistema una vez que el programa se cierra.

Así.Para responder a tu pregunta, no creo que en realidad tienen un problema aquí.Ciertamente, usted no tiene una pérdida de memoria, y de su código, no creo que haya necesidad de preocuparse, tan lejos como el consumo de memoria va bien.Siempre y cuando te asegures de que usted no está en repetidas ocasiones que la asignación de controlador de eventos sin de-la asignación de la misma (es decir, que sólo se ha puesto una vez, o que lo quite exactamente una vez por cada vez que se le asigna), que parecen estar haciendo, el código debe estar bien.

Parece que es el consejo que el cartel en tu blog estaba tratando de darle, pero ha utilizado esta alarmante de la obra "fuga", que es un miedo a la palabra, pero que muchos programadores han olvidado el verdadero significado de lo que en el mundo administrado;no se aplican aquí.

@Arturo:

...obstruir su memoria y hacer que su aplicación muy lento cuando se no recolector de basura.

Que cegadoramente obvio, y no estoy en desacuerdo.Sin embargo:

...eres una fuga de memoria para el objeto que ya no uso...porque hay una referencia a ellos.

"la memoria es asignada a un programa, y ese programa, posteriormente pierde la capacidad de acceder a ella debido a la lógica del programa de defectos" (Wikipedia, "pérdida de Memoria")

Si existe una referencia a un objeto, que su programa puede acceder, entonces por definición no es una fuga de memoria.Una fuga significa que el objeto ya no es accesible (para ti o para el sistema operativo/Marco), y no será liberado durante el tiempo de vida del sistema operativo de la sesión actual.Este no es el caso aquí.

(Siento ser una semántica de la...tal vez soy un poco de la vieja escuela, pero la fuga tiene un significado muy específico.La gente tiende a usar "pérdida de memoria" en estos días para decir nada de lo que consume de 2 kb de memoria más de lo que quieren...)

Pero claro, si no liberan a un controlador de eventos, el objeto al que está conectado no será liberado hasta que el proceso de la memoria es reclamado por el recolector de basura en la parada.Pero este comportamiento es totalmente esperado, al contrario de lo que parecen.Si usted espera que un objeto para ser reclamado, entonces usted necesita para eliminar cualquier cosa que pueda mantener la referencia vivos, incluyendo a los controladores de eventos.

La verdad verdadera,

Por supuesto tienes razón..Pero hay toda una nueva generación de programadores de haber nacido en este mundo que nunca van a tocar código no administrado, y yo creo que las definiciones de idioma se re-inventa a sí mismo una y otra vez.Pérdidas de memoria en WPF son en esta forma diferente de decir C/Cpp.

O curso a mis jefes que me he referido a ella como pérdidas de memoria..a mis compañeros de trabajo me he referido a él como un problema de rendimiento!

Refiriéndose a la de Matt problema, podría ser un problema de rendimiento que usted puede ser que necesite para hacer frente.Si usted sólo tiene que utilizar un par de pantallas y de realizar los controles de pantalla de los embarazos únicos, es posible que no vea este problema ;).

Así que (el administrador de bits), sin duda, puedo entender y simpatizar.

Pero lo que Microsoft llama, yo no creo que una "nueva" definición es adecuada.Es complicado, porque no vivimos en un 100% administrado mundo (incluso a pesar de que a Microsoft le gusta fingir que lo hacemos, la propia Microsoft de no vivir en ese mundo).Cuando usted dice que la pérdida de memoria, podría significar que un programa está consumiendo demasiada memoria (que es de un usuario de la definición), o que un administrado de referencia no será liberado hasta la salida (como aquí), o que no gestionado de referencia no está siendo debidamente limpiado (que sería una verdadera pérdida de memoria), o que el código no administrado llamado desde código administrado es una fuga de memoria (otro real de fuga).

En este caso, es obvio lo que la "pérdida de memoria" significa que, a pesar de que estamos siendo impreciso.Pero se hace muy tedioso hablar con algunas personas, que se llaman a cada sobre-consumo, o el fracaso de recopilar una pérdida de memoria;y es frustrante cuando estas personas son los programadores, los que supuestamente saben mejor.Es importante que los términos técnicos a tener inequívoca significados, creo.La depuración es mucho más fácil cuando lo hacen.

De todos modos.No me refiero a convertir esto en un etéreas discusión sobre el lenguaje.Acaba de decir...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top