MaxCapacity StringBuilder


Почему этот код создает исключение OutOfMemoryException для i = 690864192?

StringBuilder sb = new StringBuilder();
                for (int i = 0; i < Int32.MaxValue; i++)
                {
                    sb.Append("s");
                }
                Console.WriteLine(sb.ToString());
                Console.Read();

Емкость по умолчанию составляет 16 символов, но это растет при его потребности до максимума, который является int.Максимальное значение = 2,147,483,647. Так почему же, когда число символов равно 690 864 192, что намного меньше максимальной емкости, возникает исключение?

2 2

2 ответа:

Каждый раз, когда StringBuilder выделяет новый char[] (указывая на предыдущий экземпляр chunk.. что является еще одним StringBuilder).. вы оказываете безумное давление на сборщика мусора.

Существуют ограничения памяти на размер объектов. Ваш объект, скорее всего, будет максимально использовать выделенную вам память для процесса приложений до его завершения... следовательно, OutOfMemoryException в любом случае.

Последний экземпляр StringBuilder, который у вас есть, указывает на последний экземпляр перед тем, как он превысил лимит.. вот этот также указывает на предыдущий экземпляр, прежде чем он превысил лимит... и т.д. У вас есть гигантский график корней для GC, которые никогда не очищаются.

То есть в принципе у меня недостаточно оперативной памяти для хранения экземпляра StringBuilder с таким количеством символов?

Нет, нет, нет, нет.

Оперативная память не имеет значения; оперативная память не является релевантной мерой памяти уже почти два десятилетия! Виртуальное адресное пространство является соответствующей мерой.

Поразительно количество людей, которые считают, что память все еще работает так, как это было в машинах DOS в 1980-х годах. системы управляют памятью. ОЗУ-этооптимизация производительности . Память - это файл подкачки .

Подумайте об этом так. У вас есть парковка (файл подкачки), которая может вместить миллион автомобилей (страницы памяти). У вас есть подъездная дорога (RAM), которая может вместить десять автомобилей. У вас есть брелок, который может содержать тысячу ключей (виртуальная память). У тебя тысяча машин. Те десять, которые вы используете чаще всего, находятся на подъездной дорожке. Остальные 990 находятся на парковке дальше по улице.

Когда ты выбегаешь из-за отсутствия места на подъездной дорожке, вы просто перемещаете одну из машин на стоянку. (Оперативная память делает быстрый доступ к часто используемым страницам.)

Но когда вы покупаете автомобиль № 1001, ресурс, который вы исчерпали, - этоместо на брелоке , а неместо на парковке илиместо на подъездной дорожке . Вы можете сделать больше места на подъездной дорожке в любое время, и у вас есть куча дополнительного места на парковке, но ваш брелок только такой большой.

Почему это, когда число символов это 690,864,192, что намного меньше, чем максимальная емкость, не выбрасывает ли он исключение?

Вы получаете только 2 ГБ адресуемого пользователем виртуального адресного пространства на процесс на 32-разрядной машине Windows.

При двух байтах на символ, 690 миллионов символов составляет 1,4 миллиарда байт, что является огромной долей адресного пространства 2 ГБ. Вы оставляете только вокруг себя .6 ГБ, чтобы соответствовать всему остальному в процессе . В какой-то момент строителю строк потребуется выделить еще один блок и в вашем адресном пространстве нет ни одного свободного блока такого размера, поэтому выделение не выполняется.

Почему вы пытаетесь сделать это в первую очередь? Строка в 1,4 миллиарда байт-это совершенно нелепо.