2013-05-14 11 views
7

Ho scaricato un flusso come byte [] 'raw' che è di circa 36 MB. Ho poi convertire in una stringa constring.replace vs StringBuilder.replace per memoria

string temp = System.Text.Encoding.UTF8.GetString(raw) 

Poi ho bisogno di sostituire tutti "\ n" con "\ r \ n" così ho cercato

string temp2 = temp.Replace("\n","\r\n") 

ma è buttato una "memoria insufficiente " eccezione. Ho quindi provato a creare una nuova stringa con StringBuilder:

string temp2 = new StringBuilder(temp).Replace("\n","\r\n").toString() 

e non ha lanciato l'eccezione. Perché dovrebbe esserci un problema di memoria in primo luogo (mi occupo solo di 36MB qui), ma anche perché StringBuilder.Replace() funziona quando l'altro no?

+0

Ho visto quella domanda, ma ha più a che fare con le prestazioni piuttosto che con l'utilizzo della memoria. Inoltre, questo era più di un "cosa succede dietro la scena?" domanda piuttosto che un "come lo risolvo?" uno. – Aeon2058

risposta

5

Quando si utilizza:

string temp2 = temp.Replace("\n","\r\n") 

per ogni partita di "\ n" nella stringa di temperatura, il sistema crea una nuova stringa con la sostituzione.

Con StringBuilder questo non accade perché StringBuilder è modificabile, quindi è possibile modificare lo stesso oggetto senza la necessità di crearne un altro.

Esempio:

temp = "test1\ntest2\ntest3\n" 

Con Primo metodo (stringa)

string temp2 = temp.Replace("\n","\r\n") 

è equivalente a

string aux1 = "test1\r\ntest2\ntest3\n" 
string aux2 = "test1\r\ntest2\r\ntest3\n" 
string temp2 = "test1\r\ntest2\r\ntest3\r\n" 

Con Metodo Secon (Strin gBuilder)

string temp2 = new StringBuilder(temp).Replace("\n","\r\n").toString() 

equivale a

Stringbuilder aux = "test1\ntest2\ntest3\n" 
aux = "test1\r\ntest2\ntest3\n" 
aux = "test1\r\ntest2\r\ntest3\n" 
aux = "test1\r\ntest2\r\ntest3\r\n" 
string temp2 = aux.toString() 
+1

Quindi, se la mia stringa fosse lunga 36MB e avessi detto 50.000 "\ n" da sostituire, con string.Replace() questo avrebbe richiesto 36 * 50000MB per realizzare, ed è per questo che c'era un errore di memoria? Non dovresti eseguire gc su aux1, aux2, aux3 ... ecc perché non sono più necessari? – Aeon2058

+0

Questo non sembra accurato. Il codice C++ nativo che string.Replace corre è disponibile all'indirizzo https://github.com/fixdpt/shared-source-cli-2.0/blob/master/clr/src/vm/comstring.cpp#L1572. Inizializza la stringa, trovando tutti gli indici delle sottostringhe che verranno sostituite. Quindi assegna esattamente la giusta quantità di memoria basata su quello. Quindi itera nuovamente la stringa, copiando l'originale nel nuovo buffer, apportando le sostituzioni dove necessario. –

3

seguito StringBuilder da MSDN:

maggior parte dei metodi che modificano un'istanza di questa classe restituiscono un riferimento a quella stessa istanza e puoi chiamare un metodo o la proprietà sul riferimento. Questo può essere utile se si desidera scrivere una singola istruzione che concatena le operazioni successive.

Così quando si chiama replace with String il nuovo oggetto (big data - 36MB) verrà assegnato per creare una nuova stringa. Ma StringBuilder accede agli stessi oggetti di istanza e non ne crea uno nuovo.

0

La stringa è immutabile in C#. Se si utilizza il metodo string.replace(), il sistema creerà un oggetto String per ogni sostituzione. La classe StringBuilder ti aiuterà a evitare la creazione di oggetti.

1

Esiste un concetto di pressione della memoria, il che significa che più oggetti temporanei vengono creati, più spesso viene eseguita la raccolta di dati inutili.

Quindi: StringBuilder crea meno oggetti temporanei e riduce la pressione della memoria.

StringBuilder Memory

Sostituire

Abbiamo poi usare StringBuilder per sostituire caratteri in loop. Prima converti la stringa in StringBuilder, quindi chiama i metodi di StringBuilder. Questo è più veloce: il tipo StringBuilder utilizza gli array di caratteri internamente