c# memory-leaks xna

Giant Memory Leak de C#/ XNA



memory-leaks (2)

No ha publicado suficiente información para proporcionarle más que una conjetura. Aquí está mi conjetura educada:

Si estás haciendo cosas como esta en tu método Draw:

spriteBatch.DrawString(font, "Score: " + score, location, Color.Black); spriteBatch.DrawString(font, "Something else: " + foo, overHere, Color.Black); spriteBatch.DrawString(font, "And also: " + bar, overThere, Color.Black);

Entonces, cada una de esas llamadas creará una nueva string y objetos StringBuilder detrás de su espalda cada vez que se ejecuten. Debido a que están en su método Draw , cada uno probablemente se ejecute 60 veces por segundo. ¡Eso es una gran cantidad de objetos temporales asignados!

Para verificar que este es el caso, use el CLR Profiler. Parece que ya has hecho esto.

Si bien esto no es realmente una "fuga", el recolector de basura eventualmente los limpiará, este patrón de asignación no es deseable en un juego. Consulte esta publicación en el blog sobre dos métodos para tratar la recolección de basura en un juego. El Método 1 generalmente es más fácil y ofrece mejores resultados, así que lo estoy discutiendo aquí.

Vale la pena mencionar en este punto que el GC en la PC es lo suficientemente rápido como para que asignaciones como esta realmente no importen . El GC limpiará objetos pequeños (como sus cadenas temporales) con muy poca sobrecarga.

En la Xbox 360, por otro lado, incluso la producción de pequeñas cantidades de basura como esta regularmente puede causar algunos problemas graves de rendimiento. (No estoy seguro acerca de WP7, pero personalmente lo trataría como Xbox, ¡con cuidado!)

¿Cómo arreglamos esto?

La respuesta es simple: DrawString aceptará una instancia de StringBuilder en lugar de string . Cree una instancia de StringBuilder y StringBuilder utilizarla cada vez que necesite armar una cadena personalizada.

Tenga en cuenta que la conversión de un número u otro objeto a una cadena, implícitamente o mediante su método ToString() también causará asignaciones. Por lo tanto, es posible que deba escribir su propio código personalizado para anexarlo a StringBuilder sin causar asignaciones.

Aquí hay uno que uso, en la forma de un método de extensión, para agregar enteros a una cadena sin asignar:

public static class StringBuilderExtensions { // 11 characters will fit -4294967296 static char[] numberBuffer = new char[11]; /// <summary>Append an integer without generating any garbage.</summary> public static StringBuilder AppendNumber(this StringBuilder sb, Int32 number) { bool negative = (number < 0); if(negative) number = -number; int i = numberBuffer.Length; do { numberBuffer[--i] = (char)(''0'' + (number % 10)); number /= 10; } while(number > 0); if(negative) numberBuffer[--i] = ''-''; sb.Append(numberBuffer, i, numberBuffer.Length - i); return sb; } }

Esta es mi primera publicación acá. Estoy haciendo un juego en Visual Studio 2010 usando XNA, y he tenido una fuga de memoria gigante. Mi juego comienza usando 17k ram y luego después de diez minutos es hasta 65k. Ejecuté algunos perfiles de memoria, y todos dicen que se están creando nuevas instancias del objeto String, pero no están en vivo. La cantidad de instancias activas de String no ha cambiado en absoluto. También está creando instancias de Char [] (lo que espero de él), Object [] y StringBuilder. Mi juego es bastante nuevo, pero hay mucho código para publicar aquí. No tengo idea de cómo deshacerse de instancias que no están en vivo, ¡por favor ayuda!


No hay pérdidas de memoria en C # (o bueno, son muy difíciles de conseguir). Lo que estás experimentando es normal. El recolector de basura no "siente" que necesita recopilar memoria, por lo que no funciona. Siempre que la memoria se agota, se producirá la recolección de basura. Si está absolutamente seguro de no mantener referencias innecesarias a su string s, entonces todo está bien.

Si desea forzar un ciclo de GC, use GC.Collect() .