2015-05-28 13 views
6

C'è un modo per concatenare due stringhe (non definitive) senza allocare memoria?Concatenazione di stringhe senza allocazione in java

Per esempio, ho questi due stringhe:

final String SCORE_TEXT = "SCORE: "; 
String score = "1000"; //or int score = 1000; 

Quando ho concateno queste due stringhe, viene creato un nuovo oggetto String.

font.drawMultiLine(batch, SCORE_TEXT + score, 50f, 670f);//this creates new string each time 

Poiché questo viene eseguito nel ciclo di gioco principale (eseguito ~60 volte in un secondo), ci sono molte assegnazioni.

Posso farlo in qualche modo senza allocazione?

+3

Questo causa effettivamente un problema di prestazioni, o stai facendo [ottimizzazione prematura] (http://c2.com/cgi/wiki?PrematureOptimization)? – Jesper

+1

Sì, in realtà causa problemi di prestazioni, a causa del gc. Il gioco è per dispositivi mobili, e su dispositivi più lenti, gc causa il calo dei fps ... – pedja

+0

@ Kenneth Clark, il formato String crea alcuni nuovi oggetti. per esempio. 'Formatter',' Pattern' ... – pedja

risposta

4

La soluzione ovvia è di non ricreare l'uscita String su ogni frame, ma solo quando cambia.

Un modo per farlo è quello di memorizzarlo da qualche parte al di fuori del ciclo principale e aggiornarlo quando si verifica un determinato evento, cioè il "punteggio" cambia effettivamente. Nel tuo ciclo principale, quindi, utilizzi solo il prefisso creato String.

Se non è possibile/o non si desidera avere questo approccio basato su eventi, è sempre possibile memorizzare il punteggio "precedente" e concatenare una nuova stringa solo quando il punteggio precedente è diverso dal punteggio corrente.

A seconda della frequenza con cui il punteggio viene effettivamente modificato, è necessario eliminare la maggior parte delle riallocazioni. A meno che il punteggio non cambi a 60 fps, nel qual caso questo punto è completamente muto perché nessuno sarebbe in grado di leggere il testo che stai stampando.

+0

questo è in realtà il miglior suggerimento finora. Ma penso che un'idea ancora migliore sia quella di disegnare ogni stringa separatamente. Avrò ancora una chiamata, ma penso che sia molto meglio di molte allocazioni – pedja

+0

@pedja Puoi farlo anche tu, ma probabilmente dovresti allineare manualmente le due stringhe, il che potrebbe essere fattibile nel tuo caso perché la prima stringa è statica. –

+0

sì, esattamente, tx, accetterò la tua risposta – pedja

1

Non ho capito la domanda la prima volta. Hai provato a usare quanto segue?

SCORE_TEXT.concat(score); 
+0

'sb.toString();' crea una nuova stringa – pedja

+0

usa l'oggetto 'res' che è già istanziato invece di concatenarlo sul fly – nuno

+0

punteggio non è una stringa statica, viene creato dinamicamente – pedja

0

io non credo che si può compilare un valore senza allocazione di una memoria per esso .. cosa migliore che puoi fare è creare una stringa variabile globale e fornire il valore di SCORE_TEXT + punteggio ad esso. Usa quella variabile di stringa globale nel metodo font.drawMultiLine().

In questo modo è possibile ridurre al minimo la quantità di memoria allocata poiché la memoria viene allocata una sola volta e la stessa posizione viene nuovamente aggiornata &.

+0

Ciò che suggerisci è impossibile perché il punteggio è una stringa dinamica – pedja

1

Seems thatdrawMultiLine non accetta String, ma CharSequence. Quindi potresti probabilmente implementare il tuo CharSequence che in realtà non concatena due stringhe. Ecco il progetto di implementazione:

public class ConcatenatedString implements CharSequence { 
    final String left, right; 
    final int leftLength; 

    public ConcatenatedString(String left, String right) { 
     this.left = left; 
     this.right = right; 
     this.leftLength = left.length(); 
    } 

    @Override 
    public int length() { 
     return leftLength+right.length(); 
    } 

    @Override 
    public char charAt(int index) { 
     return index < leftLength ? left.charAt(index) : right.charAt(index-leftLength); 
    } 

    @Override 
    public CharSequence subSequence(int start, int end) { 
     if(end <= leftLength) 
      return left.substring(start, end); 
     if(start >= leftLength) 
      return right.substring(start-leftLength, end-leftLength); 
     return toString().substring(start, end); 
    } 

    @Override 
    public String toString() { 
     return left.concat(right); 
    } 
} 

usare in questo modo:

font.drawMultiLine(batch, new ConcatenatedString(SCORE_TEXT, score), 50f, 670f); 

Internamente nel tuo caso drawMultiline deve solo le length e charAt metodi. Utilizzando ConcatenatedString si crea solo un nuovo oggetto. Al contrario, quando si utilizza , viene creato uno StringBuilder temporaneo che crea una matrice interna char[], copia i simboli di input, ridimensiona la matrice se necessario, quindi crea l'oggetto String finale che crea la nuova matrice char[] e copia nuovamente i simboli. Quindi è probabile che ConcatenatedString sarà più veloce.

+0

ma 'left.concat (a destra);' crea una nuova stringa – pedja

+0

Solo se 'toString' o' subSequence' è chiamato. Ma è improbabile nel tuo caso. –

+0

ok, tnx, proverò – pedja

0

La stringa è progettata per essere immutabile in Java. usa StringBuilder