2010-03-20 12 views
5

Mi biblioteca DotNET pura se ejecuta como un complemento dentro de una aplicación de escritorio no administrada. He recibido un flujo constante (aunque bajo) de informes de fallos que parecen indicar un problema con los identificadores de GDI (fuentes en los mensajes de error, etc. vuelven a la fuente del sistema, se despliegan todo tipo de controles, falla masiva poco después)Gestiones GDI en una aplicación DotNET

Mis formularios tienen pocos controles, pero hago un montón de dibujo de GDI + en controles de usuario. ¿Cuál es una buena forma de decir cuántas manijas estoy usando o incluso goteando?

Gracias, David

+1

Una buena cosa para empezar es actualizar la pregunta con un ejemplo típico de cómo se ve el código de su dibujo. De esta manera, puede obtener algunas respuestas concretas sobre cosas que quizás pueda mejorar. –

Respuesta

2

He tenido que lidiar con el mismo tipo de problema en el pasado. Para inspeccionar cuántos objetos GDI está asignando su aplicación, puede usar una herramienta gratuita llamada GDIUsage.

En mi caso, la aplicación se bloqueaba porque estaba asignando más de 10.000 objetos GDI, que es un límite estricto en Windows XP. Puede valer la pena investigarlo.

he blog acerca de este problema aquí:
http://megakemp.com/2009/02/25/gdi-memory-leak-in-windows-forms/

+0

Gracias! Esto me ayudará a comenzar. –

1

Es fácil de ver desde Taskmgr.exe, ficha Procesos. Ver + Seleccionar columnas, marcar objetos GDI.

De hecho, su descripción coincide con una pérdida de identificador. Eso realmente no debería suceder en un programa administrado, el finalizador debería encargarse de que te olvides de llamar a Dispose(). A menos que no consuma una gran cantidad de espacio de montón recogido de basura. También podría ser la aplicación no administrada que se escapa maneja, lo hacen muy a menudo.

+2

Si el código administrado deja el GC para llamar al método 'Dispose', también puede ocasionar problemas, ya que GC se ejecuta en paralelo y se ejecuta a su conveniencia. Es por eso que cuando se usan objetos GDI en código administrado, es una buena práctica envolverlos entre un bloque 'using'. –

+0

Gracias nobugz. "Eso no debería suceder realmente en un programa administrado". Lo sé, y estoy bastante seguro de que no llamo Dispose on * every * Pen and Brush y GraphicsPath que creo. Dado que los problemas informados no ocurren cuando mi complemento no está cargado, asumo que es mi culpa en lugar de la aplicación no administrada. –

3

Además del monitor de rendimiento, puede probar el viejo administrador de tareas.

Compruebe la ficha Proceso y haga clic en View>Select Columns... y compruebe los objetos GDI.

+0

Gracias Paolo, desafortunadamente mi aplicación se ejecuta como un complemento dentro de una aplicación más grande y desea poder ver qué identificadores se usan solo para mi código. No estoy exactamente seguro de si esto no es posible, pero sería preferible a una visión general general. –

1

Si aún no lo hace, asegúrese de llamar a IDisposable. Deseche en cualquier objeto de dibujo GDI + que esté utilizando. Que se suele hacer esto con el constructo C# using, por ejemplo .:

using(Brush brush = ...) 
{ 
    ... 
} 

estáticas herramientas de análisis de código como FxCop o la versión incorporada en las ediciones del sistema del equipo de Visual Studio pueden ayudar a detectar casos en los que no citan a botar.

Fallo en la llamada Eliminar de esta forma es una posible fuga de identificador, ya que el identificador no se recuperará hasta que el recolector de basura lo considere oportuno.

3

Tome un vistazo a la GDIView (que es gratuito):

GDIView es una herramienta única que muestra la lista de identificadores de GDI (pinceles, plumas, fuentes, mapas de bits y otros) abierto por cada proceso. Muestra el recuento total de cada tipo de identificador GDI , así como información detallada sobre cada identificador. Esta herramienta puede ser útil para los desarrolladores que necesitan rastrear la fuga de recursos GDI en su software.

alt text http://www.nirsoft.net/utils/gdiview.gif

Nota que la actualización automática está desactivada por defecto, pero se puede activar y configurar para intervalos específicos: Options -> Auto Refresh -> Every [N] seconds

1

GDIObj, una utilidad gratuita proporcionada por Feng Yuan como una programa de ejemplo para su libro, Windows Graphics Programming: Win32 GDI and DirectDraw podría ser útil.

A diferencia de Administrador de tareas, que proporciona el recuento de un desglose más detallado de los diferentes tipos de mango GDI incluyendo DC, Región, mapa de bits, paleta, fuente, cepillo, etc.

(Sin embargo, sólo proporciona contar con información, mientras que proporciona GDIView . más detalles acerca de las asas)

2

a partir de GDIView de la respuesta de Ray Vega, encontré this tip:

[DllImport("User32")] 
extern public static int GetGuiResources(IntPtr hProcess, int uiFlags); 

    public static void GetGuiResourcesGDICount()  
    { 
     //Return the count of GDI objects.   
     Console.WriteLine("GDICount"+GetGuiResources(System.Diagnostics.Process.GetCurrentProcess().Handle, 0));  
    } 

    private void button1_Click(object sender, System.EventArgs e) 
    { 
     GetGuiResourcesGDICount(); 
    } 

GDIView informó que era objetos de fuente th se estaban filtrando; Luego agregué llamadas al GetGuiResources en nuestro código de registro para detectar en qué punto se estaba activando la creación del objeto.

En nuestro caso, teníamos el texto de un control Label actualizado cuando su padre UserControl estaba oculto en una ventana de fondo. Esto provocaría que GDI pierda identificadores de fuente. Para solucionarlo, cambiamos nuestra lógica para no actualizar el Label a menos que estuviera visible en la pantalla. Para determinar si era visible, guardamos un registro de cuándo se pintó por última vez UserControl.

Cuestiones relacionadas