Ho un'applicazione che utilizza una grande quantità di stringhe. Quindi ho qualche problema di utilizzo della memoria. So che una delle migliori soluzioni in questo caso è usare un DB, ma non posso usarlo per il momento, quindi sto cercando altre soluzioni.String VS Byte [], utilizzo memoria
In stringa C# sono memorizzati in Utf16, ciò significa che ho perso metà dell'utilizzo della memoria rispetto a Utf8 (per la maggior parte delle mie stringhe). Quindi ho deciso di usare l'array di byte della stringa utf8. Ma con mia sorpresa questa soluzione ha avuto due volte più spazio di memoria rispetto alle semplici stringhe nella mia applicazione.
Quindi ho fatto qualche semplice test, ma voglio sapere l'opinione degli esperti per essere sicuro.
Test 1: allocazione stringhe di lunghezza fissa
var stringArray = new string[10000];
var byteArray = new byte[10000][];
var Sb = new StringBuilder();
var utf8 = Encoding.UTF8;
var stringGen = new Random(561651);
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
Sb.Append((stringGen.Next(90)+32).ToString());
}
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
Sb.Clear();
}
GC.Collect();
GC.WaitForFullGCComplete(5000);
utilizzo della memoria
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
000000bf7655fcf0 303 3933750 Free
00007ffac1fd5738 10004 224695091 System.Byte[]
00007ffac1fcfc40 10476 449178396 System.String
Come possiamo vedere, i byte array prendono due volte meno spazio in memoria, nessuna vera sorpresa qui.
Test 2: Random allocazione stringa di formato (con una lunghezza realistica)
var stringArray = new string[10000];
var byteArray = new byte[10000][];
var Sb = new StringBuilder();
var utf8 = Encoding.UTF8;
var lengthGen = new Random(2138784);
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < lengthGen.Next(100); j++) {
Sb.Append(i.ToString());
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
}
Sb.Clear();
}
GC.Collect();
GC.WaitForFullGCComplete(5000);
utilizzo della memoria
00007ffac200a510 1 80032 System.Byte[][]
000000be2aa8fd40 12 82784 Free
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fd5738 9896 682260 System.Byte[]
00007ffac1fcfc40 10368 1155110 System.String
String prende un po 'meno spazio rispetto al tempo il doppio dello spazio di memoria di array di byte . Con una stringa più breve mi aspettavo un overhead maggiore per le stringhe. Ma sembra che sia il contrario, perché?
Test 3: modello di stringa corrispondente alla mia domanda
var stringArray = new string[10000];
var byteArray = new byte[10000][];
var Sb = new StringBuilder();
var utf8 = Encoding.UTF8;
var lengthGen = new Random();
for (int i=0; i < 10000; i++) {
if (i%2 == 0) {
for (int j = 0; j < lengthGen.Next(100000); j++) {
Sb.Append(i.ToString());
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
Sb.Clear();
}
} else {
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
Sb.Clear();
}
}
GC.Collect();
GC.WaitForFullGCComplete(5000);
utilizzo della memoria
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fcfc40 5476 198364 System.String
00007ffac1fd5738 10004 270075 System.Byte[]
Qui stringhe prendono molto meno spazio di memoria di byte. Questo può essere sorprendente, ma suppongo che la stringa vuota sia riferita solo una volta. È? Ma non so se questo può spiegare tutta questa enorme differenza. È qualche altra ragione? Qual è la soluzione migliore?
Perché non usare 'String.IsNullOrEmpty (StringArray [i])' ? –
@MarkJansen È solo un'illustrazione: so per certo che 'stringArray [i]' è vuoto nel ramo 'else' del condizionale' if (i% 2 == 0) ', quindi avrei potuto saltare il confronto con 'string.Empty' del tutto. – dasblinkenlight
Interessante, infatti, utilizzare un riferimento a byte vuoto per migliorare l'utilizzo della memoria molto. Ho dimenticato di dire nel mio post, che ero a 64 bit e l'unità è byte. Comunque questo non cambia l'idea della tua spiegazione, anche se ho trovato che 34 byte per un puntatore sono molti, (anche di più con i 26 byte di ogni stringa). Ho già perso la dimensione del puntatore 10K (80032 KB ovvero il 25% della dimensione della memoria utile) con System.Byte [] []. C'è un modo per evitare l'uso di così tanto indirezione? Forse non con la matrice di byte. – Edeen