2011-09-08 17 views
10

Sto lavorando a un gioco XNA di Windows Phone 7. È un porting di un gioco scritto in C++ e, come tale, sto cercando di fare il minimo riscrittura del codice del gameplay possibile.Stringhe mutabili in WP7 C#/XNA?

Garbage è un enorme problemasu WP7, perché il collettore è nongenerational e lento, quindi una collezione (che viene attivato ogni 1MB) richiede circa 10ms per MB di allocazioni. Intendo utilizzare pienamente i 90 MB massimi disponibili, quindi stiamo osservando uno stallo di ~ 900 ms ogni MB di allocazione.

Sono stato in grado di rielaborare le cose in modo che non abbiamo generato il garbage per-frame, tranne alcuni casi di stringhe.

Sembra che StringBuilder.ToString() generi rifiuti e il metodo descritto here non funzioni su WP7.

Le due cose che devo fare sono:

  • formato minuti/secondi/centesimi come mm: ss.hh per la visualizzazione sullo schermo. Apparentemente posso farlo con un StringBuilder (usando i metodi di estensione che non creano garbage da inscatolare i pollici) e visualizzare lo StringBuilder direttamente con SpriteBatch.
  • Dividere una stringa del modulo "foo.bar.baz.qux" in un array su ".", Cioè {"foo", "bar", "baz", "qux"} e copiare un elemento in un tempo in una serie di stringhe. Questo è per impostare lo stato gerarchico degli attori del gioco. È anche praticamente trasferito direttamente dal gioco originale, e molto dipende dal fatto che funzioni in questo modo. Mi piacerebbe davvero evitare di riscriverlo.

A parte la conversione di un sacco di codice per l'utilizzo di char [] anziché di stringa, esiste un modo per avere stringhe veramente modificabili senza spazzatura in C#?

+2

Solo una nota laterale mango ha GC generazionale http://blogs.msdn.com/b/abhinaba/archive/2011/04/13/generational-gc-in-windows-phone-mango.aspx – Terrance

+0

Anche questo è un modo per creare qualcosa di "più vicino" alle stringhe mutabili http://stackoverflow.com/questions/6913435/how-to-get-a-list-of-mutable-strings – Terrance

risposta

10

Perché è necessario convertire un StringBuilder in un String in primo luogo? Come hai notato, puoi passare StringBuilder direttamente nei metodi di disegno di XNA. È inoltre possibile utilizzare StringBuilder per recuperare stringhe:

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

Le uniche cose che si desidera evitare con StringBuilder sono ToString() e AppendFormat(). Nessuno degli altri metodi di formattazione (a mia conoscenza) genera spazzatura. Aggiornamento : ho sbagliato. Scrivi i tuoi metodi di estensione. Un rundown è disponibile qui: Avoiding garbage when working with StringBuilder

È relativamente facile scrivere un metodo che dividerà una stringa in sottostringhe in base a un determinato delimitatore. Ricorda che String.Split() è un male per due motivi - in primo luogo, perché assegna nuove stringhe; e in secondo luogo, perché lo alloca un nuovo array. L'immutabilità delle stringhe è solo metà del tuo problema.

Considerare i seguenti metodi di estensione per StringBuilder. Non ho testato a fondo questo codice, ma dovrebbe darti un'idea generale. Si noti che si prevede di passare in un array pre-assegnato, che verrà poi compilato.

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

La formattazione di oggetti non stringa (ad esempio: numeri) genera garbage (chiama il loro metodo 'ToString'). Ma è piuttosto semplice scrivere un metodo di estensione senza spazzatura per accodare interi (o molti altri tipi, in realtà). Puoi trovare esempi abbastanza facilmente online. –

+0

Una rapida occhiata alla fonte decompilata conferma che sei corretto. Non sono sicuro del perché ho pensato diversamente. Ma sì, puoi aggirare questo. –

0

che sto cercando di fare il meno riscrittura del codice di gioco possibile.

Attenzione, potrebbe essere necessario più tempo per la riscrittura. Cole Campbell ha ragione, non ha senso chiamare ToString() mentre vuoi disegnarlo. XNA ha il metodo draw che prende StringBuldier e funziona bene nel mio gioco.

Un'altra soluzione al tuo problema: crea un Hashset globale delle stringhe e impostalo quando carichi il gioco o il livello per evitare la pressione di raccolta.

Cerca di fare il più possibile quando carichi il gioco.