Mam aplikację, która używa dużej ilości ciągów. Mam więc problem z wykorzystaniem pamięci. Wiem, że jednym z najlepszych rozwiązań w tym przypadku jest użycie DB, ale nie mogę tego teraz użyć, więc szukam innych rozwiązań.String VS Byte [], wykorzystanie pamięci
W ciągu C# są przechowywane w Utf16, co oznacza, że straciłem połowę użycia pamięci w porównaniu do Utf8 (dla większej części moich ciągów). Postanowiłem więc użyć tablicy bajtowej ciągu utf8. Ale ku mojemu zaskoczeniu to rozwiązanie wymagało dwukrotnie więcej miejsca w pamięci niż proste napisy w mojej aplikacji.
Przeprowadziłem prosty test, ale chcę się dowiedzieć opinii ekspertów.
Test 1: przydział ciągów stała długość
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);
Memory Usage
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
000000bf7655fcf0 303 3933750 Free
00007ffac1fd5738 10004 224695091 System.Byte[]
00007ffac1fcfc40 10476 449178396 System.String
Jak widzimy, bajty tablice wziąć dwa razy mniej miejsca w pamięci, nie ma tu prawdziwą niespodziankę.
Test 2: Losowy przydział rozmiar string (realistyczny długości)
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);
Memory Usage
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 trwa trochę mniej miejsca niż dwukrotność czasu przestrzeń pamięci tablicy bajtów . Przy krótszym łańcuchu spodziewałem się większego nakładu na struny. Ale wydaje się, że przeciwieństwem jest, dlaczego?
Test 3: model String odpowiadający mojej aplikacji
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);
wykorzystanie pamięci
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fcfc40 5476 198364 System.String
00007ffac1fd5738 10004 270075 System.Byte[]
Tutaj ciągi wziąć dużo mniej miejsca w pamięci niż bajt. Może to być zaskakujące, ale przypuszczam, że ten pusty łańcuch odnosi się tylko raz. Czy to jest? Ale nie wiem, czy to może wyjaśnić całą ogromną różnicę. Czy to jakiś inny powód? Jakie jest najlepsze rozwiązanie?
Dlaczego nie używać 'string.IsNullOrEmpty (stringArray [i])' ? –
@MarkJansen To tylko ilustracja: wiem na pewno, że 'stringArray [i]' jest puste w gałęzi 'else' warunku' if (i% 2 == 0) ', więc mogłem pominąć porównanie z 'string.Empty' łącznie. – dasblinkenlight
Interesujące, w rzeczy samej, użycie referencji pustej bajtów znacznie poprawia wykorzystanie pamięci. Zapomniałem powiedzieć w moim poście, niż byłem w 64 bitach, a jednostka to bajty. W każdym razie nie zmienia to idei twojego wyjaśnienia, nawet gdybym znalazł 34 bajty dla wskaźnika, to dużo (nawet więcej z 26 bajtowym narzutem każdego ciągu). Już straciłem rozmiar wskaźnika 10K (80032 KB, tj. 25% użytecznego rozmiaru pamięci) z System.Byte [] []. Czy istnieje sposób na uniknięcie użycia tak dużej ilości informacji? Może nie z tablicą bajtów. – Edeen