Может ли обновление памяти с 2 до 4 ГБ предотвратить исключения переполнения стека? - PullRequest
8 голосов
/ 03 июня 2009

Мой компьютер имеет 2 ГБ оперативной памяти. Когда я формирую трехмерный объект-сетку, имеющий массив из 70 000 элементов в C # 2008 Express Edition, я получаю сообщение об ошибке «Исключение переполнения стека обработано ...». Если я обновлю ОЗУ с 2 ГБ до 4 ГБ, смогу ли я преодолеть это сообщение об ошибке?

Ответы [ 7 ]

19 голосов
/ 03 июня 2009

Почти наверняка не . Переполнение стека (а не нехватка памяти) означает, что вы использовали выделенное стек пространство - но стек (условно говоря) мал. куча - это то, где все это происходит ...

Параметры:

  • исправьте вашу бесконечную ошибку рекурсии ...
  • переместить данные в массив / список / какое-нибудь хранилище на основе кучи (где оно находится в данный момент?)
  • избегать глубокой рекурсии
  • избегайте негабаритных структур ... у вас есть большие толстые структуры, которые действительно должны быть классами? (копирует себя, если ты так моргнешь)
  • увеличить пространство стека , если , вы уверены, что вы только что опрокинули его, и это не стоит большого рефакторинга (я ненавижу этот ответ) - чтобы сделать это, вам нужно будет порождать ваш собственный поток с большим стеком
11 голосов
/ 03 июня 2009

Нет. Увеличение ОЗУ не увеличивает размер стека.

Вы пишете код, который вызывает переполнение стека (возможно, из-за рекурсии), и вам нужно это исправить.

3 голосов
/ 03 июня 2009

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

Прежде всего, поскольку я много раз видел эту ошибку, давайте поговорим о модели памяти операционной системы.

Почти каждая пользовательская операционная система (я думаю, здесь, на Linux, Windows, BSD и т. Д.) Использует модель виртуальной памяти. Модель виртуальной памяти означает, что каждой программе предоставляется полный доступ к частной виртуальной памяти, то есть представление памяти, которая не должна иметь соответствующую физическую память.

Размер этой виртуальной памяти равен диапазону, к которому может обращаться один регистр компьютера. В 32-разрядных операционных системах это означает около 4 ГБ. Теперь, независимо от того, сколько фактической памяти имеет ваша система, ваша программа всегда будет думать, что он имеет 4 ГБ.

Теперь эти 4 ГБ фактически распределяются между вашей программой и пространством, которое операционная система резервирует для обработки данных в режиме ядра, а также для поддержки структур, необходимых вашей программе. Практически вы можете рассчитывать примерно на 2 или 3 ГБ в зависимости от вашей конфигурации (конфигурации вашей ОС). Все это не имеет никакого отношения к объему физической памяти, который у вас есть, вы можете иметь 256 МБ ОЗУ, но ваша программа будет считать, что в его распоряжении 2 ГБ.

Когда вы выделяете память, система обычно не предоставляет именно тот объем памяти, который вы запрашиваете. Вместо этого он использует страницы, которые представляют собой блоки зарезервированной памяти (например, 4 КБ), назначенные вашему процессу. Когда вы делаете это, ОС регистрирует эту «страницу» как выделенную, но она все еще находится в виртуальной памяти. Внутренне ОС управляет тем, какие из этих страниц хранятся в физической памяти, а какие находятся в разделе подкачки (на жестком диске). По этой причине увеличение оперативной памяти повышает производительность (больше страниц может находиться в основной памяти одновременно, и вам приходится меньше читать с жесткого диска), но не поможет с переполнением стека (или исключением из-за нехватки памяти кстати).

И это , почему увеличение вашей оперативной памяти не поможет.

Наконец, об исключении переполнения стека ... ну, трудно увидеть, не увидев реальный код, некоторые хорошие ответы уже были даны.

В основном переполнение стека происходит из-за бесконечной рекурсии, прямой или косвенной (A -> B -> C -> A), но в вашем конкретном случае я бы сказал, что вы просто выделяете много данных в стек.

У вас есть массив размером 70000. Я предполагаю, что массив полон типов значений, которые расположены в стеке, который, если я правильно помню (и, пожалуйста, не принимайте это как факт), составляет 1 МБ в .NET, что может быть причиной того, что вы получаете переполнение вашего стека.

2 голосов
/ 03 июня 2009

Переполнение стека может означать бесконечную рекурсию ИЛИ очень глубоко вложенную.

Кстати, если у вас есть хвостовые рекурсивные методы, JITter x64 оптимизирует их, и вы вообще не столкнетесь с переполнением стека (а ваша бесконечная рекурсия будет ... ну, конечно, бесконечной).

Таким образом, вы можете перейти на 64-битную ОС или исправить свой код, чтобы не попасть в эту проблему (что скорее ошибка, чем слишком глубокая вложенная рекурсия ...)

2 голосов
/ 03 июня 2009

Наверное, нет. Вы должны увеличить размер стека , это то, что говорится в сообщении об ошибке

Редактировать: Или исправьте бесконечную рекурсию, которую вы, вероятно, имеете в своем коде.

1 голос
/ 03 июня 2009

На самом деле нет. Но у меня есть другая причина: Windows XP может обрабатывать только до 2 ГБ, если вы не укажете конкретный параметр загрузки в boot.ini. (Параметр / 3gb.) В лучшем случае Windows XP и Vista будут иметь до 3 ГБ оперативной памяти, и это в основном предел для Windows. См. Эта ссылка для получения дополнительной информации об этих пределах.

Увеличение объема ОЗУ и исправление приложения до уровня, превышающего 2 ГБ, может устранить переполнение стека, поскольку это может увеличить размер вашего стека. Это также может просто отсрочить момент переполнения стека, поскольку, как уже было предложено, ваш код находится в бесконечном рекурсивном цикле и будет продолжать работать, пока не закончатся ресурсы.

Если вы используете рекурсию, помните об этом: все, что вы делаете с помощью рекурсии, может быть переписано без использования рекурсии. Из этого правила нет исключений, хотя код будет легче читать.

0 голосов
/ 22 января 2013

Я не знаю для C #, но в Java ошибка stackoverflow означает, что вы создаете экземпляр класса в классе, который уже был создан в классе, который вы пытаетесь создать

...