У меня есть приложение, которое использует большое количество строк. Поэтому у меня есть проблема с использованием памяти. Я знаю, что одним из лучших решений в этом случае является использование БД, но я не могу использовать это на данный момент, поэтому я ищу другие решения.
В С# строка хранится в Utf16, это означает, что я потерял половину использования памяти по сравнению с Utf8 (для большей части моих строк). Поэтому я решил использовать байтовый массив строки utf8. Но, к моему удивлению, это решение заняло в два раза больше пространства памяти, чем простые строки в моем приложении.
Итак, я сделал простой тест, но я хочу знать мнение экспертов, чтобы быть уверенным.
Тест 1: выделение строк фиксированной длины
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);
Использование памяти
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
000000bf7655fcf0 303 3933750 Free
00007ffac1fd5738 10004 224695091 System.Byte[]
00007ffac1fcfc40 10476 449178396 System.String
Как мы видим, байт-массивы занимают в два раза меньше места в памяти, здесь нет ничего удивительного.
Тест 2: распределение строки произвольного размера (с реалистичной длиной)
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);
Использование памяти
00007ffac200a510 1 80032 System.Byte[][]
000000be2aa8fd40 12 82784 Free
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fd5738 9896 682260 System.Byte[]
00007ffac1fcfc40 10368 1155110 System.String
Строка занимает немного меньше места, чем в два раза больше пространства памяти массива байтов. С более короткой строкой я ожидал больших накладных расходов для строк. Но кажется, что обратное, почему?
Тест 3: Строковая модель, соответствующая моему приложению
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);
Использование памяти
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fcfc40 5476 198364 System.String
00007ffac1fd5738 10004 270075 System.Byte[]
Здесь строки занимают гораздо меньше места памяти, чем байт. Это может быть удивительно, но я полагал, что пустая строка ссылается только один раз. Это? Но я не знаю, может ли это объяснить всю эту огромную разницу. Это какая-то другая причина? Какое наилучшее решение?