2011-09-08 6 views
10

Estoy trabajando en un juego Windows Phone 7 XNA. Es un puerto de un juego escrito en C++, y como tal, intento hacer la menor reescritura del código de juego posible.Cadenas mutables en WP7 C#/XNA?

basura es un gran problemaen WP7, debido a que el colector es nongenerational y lento, por lo que una colección (que se activa cada 1 MB) dura aproximadamente 10 ms por MB de asignaciones. Tengo la intención de utilizar el máximo de 90 MB disponible, por lo que estamos viendo un puesto de ~ 900 ms por cada MB de asignación.

He podido volver a trabajar las cosas para que no tengamos basura generada por cuadro, excepto en algunos casos de cadenas.

Parece que StringBuilder.ToString() genera basura, y el método descrito here no funciona en WP7.

Las dos cosas que tengo que hacer son: minutos

  • Formato/segundos/centésimas como mm: SS.HH para la visualización de la pantalla. Aparentemente puedo hacer eso con un StringBuilder (usando métodos de extensión que no crean basura del boxeo de las entradas) y mostrar el StringBuilder directamente con SpriteBatch.
  • Dividir una cadena de la forma "foo.bar.baz.qux" en una matriz en '.', Es decir {"foo", "bar", "baz", "qux"} y copiar un elemento en una tiempo en una serie de cadenas. Esto es para establecer el estado jerárquico de los actores del juego. También está directamente portado del juego original, y depende bastante de que funcione de esta manera. Realmente me gustaría evitar reescribirlo.

Si no se convierte gran cantidad de código para usar char [] en lugar de cadena, ¿hay alguna forma de tener cadenas mutables sin basura en C#?

+2

Sólo una nota al margen mango tiene Generational GC http://blogs.msdn.com/b/abhinaba/archive/2011/04/13/generational-gc-in-windows-phone-mango.aspx – Terrance

+0

También esto es una forma de hacer algo "más cercano" a las cadenas mutables http://stackoverflow.com/questions/6913435/how-to-get-a-list-of-mutable-strings – Terrance

Respuesta

10

¿Por qué necesita convertir un StringBuilder en un String en primer lugar? Como ha notado, puede pasar StringBuilder directamente en los métodos de dibujo de XNA. También se puede utilizar para recuperar StringBuilder subseries:

substringBuilder.Length = 0; 
for (int i = start; i <= end; i++) 
    substringBuilder.Append(originalBuilder[i]); 

Las únicas cosas que desea evitar con StringBuilder son ToString() y AppendFormat(). Ninguno de los otros métodos de formateo (que yo sepa) genera basura. Actualización: estaba equivocado. Escribe tus propios métodos de extensión. Un resumen está disponible aquí: Avoiding garbage when working with StringBuilder

Es relativamente fácil escribir un método que dividirá una cadena en subcadenas basadas en un delimitador dado. Solo recuerde que String.Split() es malo para dos razones - primero, porque asigna nuevas cadenas; y segundo, porque asigna una nueva matriz. La inmutabilidad de las cadenas es solo la mitad de tu problema.

Considere los siguientes métodos de extensión para StringBuilder. No he probado exhaustivamente este código, pero debería darle una idea general. Tenga en cuenta que espera que pase una matriz preasignada, que luego se completará.

public static void Substring(this StringBuilder source, Int32 start, Int32 count, StringBuilder output) 
{ 
    output.Length = 0; 
    for (int i = start; i < start + count; i++) 
    { 
     output.Append(source[i]); 
    } 
} 

public static int Split(this StringBuilder source, Char delimiter, StringBuilder[] output) 
{ 
    var substringCount = 0; 
    var substringStart = 0; 
    for (int i = 0; i < source.Length; i++) 
    { 
     if (source[i] == delimiter) 
     { 
      source.Substring(substringStart, i - substringStart, output[substringCount]); 
      substringCount++; 
      substringStart = i + 1; 
     } 
    } 
    if (substringStart < source.Length - 1) 
    { 
     source.Substring(substringStart, source.Length - substringStart, output[substringCount]); 
     substringCount++; 
    } 
    return substringCount; 
} 
+1

El formateo de objetos que no sean cadenas (por ej .: números) lo hará generar basura (llama a su método 'ToString'). Pero es bastante trivial escribir un método de extensión libre de basura para agregar enteros (o la mayoría de los otros tipos, realmente). Puede encontrar ejemplos bastante fácilmente en línea. –

+0

Un vistazo rápido a la fuente descompilada confirma que estás en lo correcto. No estoy seguro de por qué pensé lo contrario. Pero sí, puedes evitar esto. –

0

estoy tratando de hacer lo menos reescritura del código de juego como sea posible.

Ten en cuenta que la reescritura puede llevar más tiempo. Cole Campbell tiene razón, no tiene sentido llamar a ToString() mientras lo quieres dibujar. XNA tiene un método de dibujo que usa StringBuldier y funciona bien en mi juego.

Otra solución a su problema: haga un HashSet global de sus cadenas y configúrelo cuando cargue el juego o el nivel para evitar la presión de la colección.

Intenta hacer todo lo posible cuando cargas el juego.