Во-первых, строки в .net - это последовательность слов UTF-16, поэтому каждый символ занимает 2 байта. Чтобы получить размер строки в памяти в байтах, нужно умножить ее длину на 2 (игнорируя заголовок экземпляра CLR).
Console.WriteLine($"Current Size in GB - {text.Length * 2.0 /1024/1024/1024}");
Еще одно ограничение - это размер массива в .NET, прочитайте примечания здесь , как заметил @TheGenral. Существует 2 ограничения: максимальный размер (2 ГБ) и максимальный индекс.
Ниже приведена измененная версия вашего теста:
var text = "Test content";
long length = text.Length;
try
{
while (true)
{
var currentLength = text.Length;
Console.WriteLine($"Current Length - {currentLength}");
Console.WriteLine($"Current Size in GB - {text.Length * 2.0 / 1024 / 1024 / 1024}");
text += new string('a', 500 * 1024*1024);
length = currentLength;
GC.Collect();
}
}
catch (OutOfMemoryException e)
{
Console.WriteLine(e);
}
StringBuilder
разница версий:
var text = new StringBuilder("Test content");
...
text.Append('a', 500 * 1024*1024);
Если вы не включите gcAllowVeryLargeObjects , вы получите OOM с элементами 1B.
Мне не удалось получить элементы 2B с использованием конкатенации строк, но если вы переделаете этот тест с использованием StringBuilder
, то вы сможете получить 2B символов. В этом случае вы столкнетесь со вторым ограничением: массивы не могут содержать более 2 миллиардов элементов. Здесь - обсуждение верхнего предела.
В обсуждается этот поток максимальная длина строки.
Если вы запустите этот код в Release
В режиме вы увидите, что потребление памяти процессом почти равно размеру строки в выводе консоли.
Еще одна интересная вещь, которую я заметил и не могу объяснить, это то, что в StringBuilder
, gcAllowVeryLargeObjects
и Debug
mode I 'Я могу достичь 4 ГБ, но в режиме Release
он почти достигает 3 ГБ. Приветствуются комментарии, почему это происходит:)