2009-04-15 14 views
16

Soy consciente de que la mejor práctica es llamar a Dispose en cualquier objeto que implementa IDisposable, especialmente objetos que se colocan los recursos finitos como identificadores de archivos, sockets, GDI trata, etc.¿Qué tan importante es deshacerse de una fuente realmente?

Pero estoy corriendo en un caso donde tengo un objeto que tiene una fuente, y tendría que aplomar IDisposable a través de varias capas de objetos, y revisar muchos usos, para asegurarme de que siempre obtenga la fuente eliminada. Y me pregunto si vale la pena la complejidad.

Sería una cosa si Font envolviera un HFONT, porque los recursos de GDI son system-global. Pero Font no ajusta un controlador GDI; es GDI +, que es un sistema completamente separado, y por lo que yo entiendo, es un proceso local, no un sistema global como GDI. Y a diferencia de Image, Font no se aferra a los recursos del sistema de archivos (que yo sepa, de todos modos).

Entonces mi pregunta es: ¿Cuál es el costo real de dejar que Font obtenga basura recolectada?

Sé que haría un pequeño golpe para el finalizador, pero si el número de fuentes "filtradas" es pequeño (digamos media docena), ese golpe honestamente no sería notable. Además del finalizador, esto no parece muy diferente de asignar una matriz de tamaño medio y dejar que el GC lo limpie; es solo memoria.

¿Hay costos que no conozco para permitir que una fuente obtenga GCed?

Respuesta

5

Respuesta simple: si es sólo a unos pocos, entonces no. Si es mucho, entonces sí. Si su aplicación ya está estresando al recolector de basura, entonces sí. Utilizaría perfmon para ver la cantidad de objetos que están sentados, y el número que se promociona a las generaciones superiores, y luego decidir.

4

El problema es que la recolección de basura solo ocurre cuando hay presión de memoria. A menudo, los controladores no administrados son más restringidos que la memoria, por lo que puede quedarse sin controladores antes de que ocurra GC, lo que ocasiona errores.

Pero para una o dos instancias de Font, no le hará mucho daño.

Un problema mayor es que algunos de los objetos son compartidos y no debe (o no puede) ser eliminados antes de tiempo ...

+0

"A menudo, los controladores no administrados son más restringidos que la memoria" - Claro. ¿Pero eso es cierto para los identificadores de fuente GDI + específicamente? Esa es parte de mi pregunta. –

4

¿Por qué no desecharía una vez que haya terminado? El hecho de que tengamos barrenderos no significa que debamos andar tirando basura por las calles. Sin embargo, en el ejemplo dado, si la fuente es necesaria durante el tiempo de vida del objeto, entonces deseche la fuente en ese objeto. Hay muchas cosas que simplificarían mi código también, pero eso no justifica esos cambios; a veces hay cosas que debes hacer, aunque sea un dolor.

Siempre es una buena idea ordenar después de ti mismo. Cuando ya no necesite algo, deséchelo. De esta forma, puede evitar las desagradables condiciones de carrera, las excepciones de falta de memoria, las fallas de dibujo y las largas recolecciones de basura con gran intensidad de procesador.

Me parece que es una buena práctica deshacerse de los objetos desechables si ya no los necesita a menos que exista una razón justificada para no hacerlo (como que no es el propietario del objeto). Es más difícil rastrear la causa raíz de un problema que codificar defensivamente desde el principio.

En cuanto a la fuente, MSDN says:

llamar siempre a botar antes de soltar su última referencia a la fuente.De lo contrario, los recursos que está utilizando no se liberarán hasta que el recolector de elementos no utilizados invoque el método Finalize del objeto Font.

No dice cuáles son los recursos, pero el hecho de que indiquen explícitamente que esto debe hacerse implica implícitamente la importancia de llamar a Dispose.

+5

¿Por qué no te deshaces de él? Bueno, el OP dijo por qué: porque simplificaría tremendamente su código. –

+2

Cuando la propiedad Fuente de un control (o propiedad de Imagen, o lo que sea) se establece en un objeto que tengo, ¿en qué casos el control hace una copia del objeto (en cuyo caso debo descartarlo y dejar que se deshaga de él?), y en qué casos espera el control seguir utilizando el objeto pasado? Si tuviera mi druthers, habría una manera de especificar si un control debería asumir la propiedad de un objeto transferido, pero como no existe, ¿qué debería hacer uno? – supercat

+0

@supercat: la documentación debe indicarle cuáles son las reglas con respecto a la propiedad. Sin embargo, al menos debe suponer que mientras el control hace referencia a la fuente, no debe desecharlo. Sin embargo, esperaría que el Control disponga la fuente cuando se elimine, pero no estoy seguro. –

1

Los finalizadores se incluyen específicamente en las clases porque la limpieza es necesaria. Independientemente de si tiene una cantidad grande o pequeña de objetos para limpiar, es una buena práctica limpiarlos.

El GC fue creado para tener una pseudo-mente propia. Al deshacerse de sus objetos correctamente, está permitiendo que el GC haga lo que estaba hecho.

Sin embargo, si está creando una gran cantidad de objetos de fuentes y desechando todos ellos, puede ser beneficioso llamar al GC en la generación apropiada (probablemente generación 0) cada cierto tiempo para iniciar una limpieza de GC usted mismo dependiendo de qué tipo de otros objetos esté creando en gran número. Su objetivo debe ser mantener los objetos que sabe que no está utilizando durante mucho tiempo promovidos a las generaciones mayores. Esto mantiene el trabajo del GC pobre & medio.

Simplemente use su mejor juicio y todo irá bien. Pero, de hecho, elimine cualquier objeto con un finalizador como su práctica habitual.

2

¿Qué tan importante es la eliminación de nada, de verdad? En mi humilde opinión, cuando comienzas a hacer este tipo de preguntas, parece que tienes un problema de diseño en tu código. Siempre debe deshacerse de cosas que ya no necesita; eso se llama programación responsable.

Posibles soluciones a su problema:

  • No deje pasar alrededor de los objetos como Fonts. Implemente la lógica de uso de fuente en un solo lugar (una clase), agregue la Fuente como un campo de esa clase e implemente IDisposable para esa clase.

  • implementar una clase de caché de fuentes - en lugar de crear nuevos objetos Font utilizando el operador new todo su código, utilice esta clase para obtener la Font deseada. La clase puede tener la lógica para reutilizar las Fuentes existentes, si es posible. O para mantener las últimas 10 fuentes en la memoria y deshacerse de las demás. Implemente IDisposable para el caché, que se invocará una vez en el ciclo de vida de su aplicación.

+0

¿Cómo sabría la clase Font Cache cuando las fuentes ya no se usan? ¿Tendría que "devolver" la fuente al caché? – Arafangion

+0

Sí, debería haber una forma de decirle que ya no necesita la fuente. Usualmente hago esto usando algún tipo de clase 'Lease' que implementa' IDisposable', y en el método 'Dispose()' contacta con el caché y le dice que disminuya el recuento de referencias. El mismo patrón se puede usar para las fábricas. –

+0

¿No es eso volver al punto uno, entonces? Al menos, sin embargo, ahora tiene un administrador que administra sus fuentes supuestamente caras, pero eso plantea la pregunta: ¿por qué no debería simplemente asumir que el constructor/fábrica y el recolector de basura no pueden hacer la tarea en la mayoría de situaciones? – Arafangion

-2

Tengo al menos otra aplicación ejecutándose que usa .NET runtime. Sigo recibiendo OutOfMemoryExceptions. Sería bueno hacer que tu aplicación se comporte para que otras aplicaciones no emitan excepciones cuando no pueden obtener suficientes recursos.

Cuestiones relacionadas