Когда вы беспокоитесь о размере стека?

Когда вы программируете на языке, который позволяет использовать автоматическое распределение для очень больших объектов, когда и как вы беспокоитесь о размере стека? Существуют ли какие-либо эмпирические правила для определения размера стека?

Ответы

Ответ 1

Когда вы программируете на языке, который позволяет вам использовать автоматическое распределение для очень больших объектов...

Если я хочу выделить очень большой объект, то вместо этого в стеке я мог бы выделить его в куче, но упакован в auto_ptr (в этом случае он будет освобожден, когда он выйдет из области видимости, так же, как объект-резидент, но не беспокоясь о размере стека).

... когда и как вы беспокоитесь о размере стека?

Я использую стеки консервативно по привычке (например, любой объект размером более 512 байт выделяется в куче), и я знаю, насколько большой стек (например, по мегабайту по умолчанию), и поэтому знаю, что я не нужно беспокоиться об этом.

Существуют ли какие-либо эмпирические правила для определения размера стека?

  • Очень большие объекты могут взорвать стек
  • Очень глубокая рекурсия может взорвать стек
  • Размер стека по умолчанию может быть слишком большим (занять слишком много полной памяти), если есть много потоков, и если вы используете встроенное устройство с ограниченной памятью, в этом случае вам может понадобиться использовать O/S API или компоновщик, чтобы уменьшить размер стека на поток.

Ответ 2

Вы заботитесь об этом на микроконтроллере, где вам часто приходится явно указывать пространство стека (или вы получаете все, что осталось после того, как ОЗУ будет использоваться для статического распределения + любое пространство программ RAM).

Ответ 3

Вы начинаете беспокоиться о размере стека, когда

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

Ответ 4

Если вы пишете небольшую небольшую встроенную платформу, вы все время об этом беспокоитесь, но вы также точно знаете, насколько она велика, и, вероятно, есть некоторые полезные инструменты для поиска метки воды в стеке.

Если вы этого не сделаете, тогда не беспокойтесь, пока ваша программа не сработает:) Если вы не распределяете серьезно огромные объекты (многие десятки KB), то это никогда не будет проблемой.

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

Ответ 5

Я никогда не беспокоюсь об этом. Если есть переполнение стека, я скоро узнаю об этом. Кроме того, на С++ на самом деле очень сложно создавать очень большие объекты в стеке. Единственный способ сделать это:

struct S {
   char big[1000000];
};

но использование std::string или std::vector устраняет эту проблему.

Ответ 6

Не следует ли избегать использования стека для выделения больших объектов в первую очередь? Использовать кучу, нет?

Ответ 7

мой опыт: когда вы используете рекурсивные функции, позаботьтесь о размере стека!

Ответ 8

Когда вы беспокоитесь о размере стека?

Никогда.

Если у вас проблемы с размером стека, это означает, что вы делаете что-то еще неправильно и должны исправить это, а не беспокоиться о размере стека.
Для instace:

  • Выделение необоснованно больших структур в стеке - не делайте этого. выделять в кучу.
  • Имея смехотворно длинную рекурсию. Я имею в виду порядок рисования изображения и итерации по пикселям с помощью рекурсии. - найти лучший способ сделать это.

Ответ 9

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

CreateThread по умолчанию выделяет только 0x100000 байт для стека.

Ответ 10

Я беспокоюсь о размере стека на встроенных системах, когда стек вызовов идет очень глубоко, и каждая функция выделяет переменные (в стеке). Как правило, паника развивается, когда система неожиданно падает из-за изменения переменных в стеке (переполнение стека).

Ответ 11

Сыграл эту игру много на Symbian: когда использовать TBuf (строка с хранилищем в стеке) и когда использовать HBufC (которые выделяют хранилище строк в куче, например std::string, поэтому вам нужно справиться с функцией "Оставить", и ваша функция нуждается в отказе).

В то время (может быть, еще не уверен), по умолчанию в потоках Symbian было 4k стека. Чтобы манипулировать именами файлов, вам нужно рассчитывать на использование до 512 байт (256 символов).

Как вы можете себе представить, полученная мудрость "никогда не помещала имя файла в стек". Но на самом деле оказалось, что вы можете уйти с ним гораздо чаще, чем вы думаете. Когда мы начали запускать реальные программы (TM), например игры, мы обнаружили, что в любом случае нам нужен был больше, чем размер стека по умолчанию, и это было связано не с именами файлов или с другими конкретными крупными объектами, это было связано со сложностью игровой код.

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

Ответ 12

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

Ответ 13

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

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

Если процессор не имеет управления памятью или блока защиты памяти, вы должны быть особенно осторожны. Но событие с каким-то MMU или MPU, аппаратное обеспечение может не обнаружить переполнение стека. Одна общая схема, резервирующая страницу под стеком, чтобы перехватить переполнение, терпит неудачу, если большой объект стека больше, чем страница. Там может быть стопка другого потока, сидящего там, и упс! вы просто создали очень неприятную, трудно найти ошибку.

Неограниченная рекурсия обычно легко улавливается, потому что рост стека обычно мал и вызывает аппаратную защиту.

Ответ 14

При принятии решения о том, следует ли выделять объекты в стеке против кучи, есть также первоочередные проблемы, которые необходимо учитывать. Распределение памяти в стеке происходит очень быстро - это просто связано с перемещением указателя стека, тогда как динамическое распределение/освобождение с использованием new/delete или malloc/free довольно дорого, особенно в многопоточном коде, который не имеет кучи на поток. Если у вас есть функция, которая вызывается в узком цикле, вы можете ошибаться на стороне размещения больших объектов в стеке, сохраняя в себе все многопотоковые оговорки, упомянутые в других ответах, даже если это означает, что нужно увеличить стек пространство, которое позволит большинству линкеров.

Ответ 15

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

Я как-то написал парсер CSV и во время игры, пытаясь получить максимальную производительность, я выделял из стека тысячи буферов в 1K. Производительность была звездной, но оперативная память увеличилась примерно до 1 ГБ по сравнению с обычной 30 МБ. Это связано с тем, что каждая ячейка в файле CSV имела фиксированный размер 1K-буфера.

Как все говорят, если вы не делаете рекурсию, вам не нужно беспокоиться об этом.

Ответ 16

  • Когда код, который вы написали для ПК, внезапно должен запускаться на мобильном телефоне
  • Когда код, который вы портировали для запуска на мобильном телефоне, внезапно должен работать на DSP

(И да, это реальный snafus.)

Ответ 17

Вы беспокоитесь об этом, когда вы пишете обратный вызов, который будет вызываться из потоков, созданных средой выполнения, которую вы не контролируете (например, время выполнения MS RPC) с размером стека по усмотрению этой среды выполнения. Как-то как это.

Ответ 18

У меня возникли проблемы с запуском пространства стека, когда:

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

При условии, что I:

  • Выделить большие объекты в куче (например, используя "auto_ptr foo = new Foo" вместо "Foo foo" )
  • Используйте рекурсию разумно.

У меня обычно нет проблем, поэтому, к сожалению, не знаю, какие хорошие по умолчанию должны быть.

Ответ 19

Вы начинаете беспокоиться о размере стека, когда:

  • при сбое вашей программы - обычно эти ошибки обычно кажутся странными в первый раз, когда вы их видите:)
  • вы используете алгоритм, который использует рекурсию и имеет пользовательский ввод как один из его параметров (вы не знаете, сколько стека может использовать ваш алгоритм)
  • вы работаете на встроенных платформах (или платформах, где важно каждый ресурс). Обычно на этих платформах стек выделяется до создания процесса, поэтому должна быть сделана хорошая оценка требований к стеку.
  • вы создаете объекты в стеке в зависимости от некоторых параметров, изменяемых пользователем (см. пример ниже)
  • когда код, выполняемый в потоке/процессе/задаче, имеет значение очень, и есть много вызовов функций, которые проникают глубоко в стек и генерируют огромный стек вызовов. Обычно это происходит в больших рамках, которые объединяют множество триггеров и обработки событий (GUI-инфраструктура, например: receive_click- > find_clicked_window- > send_msg_to_window- > process_message- > process_click- > is_inside_region- > trigger_drawing- > write_to_file- > ...). Короче говоря, вы должны беспокоиться о стеке вызовов в случае сложного кода или неизвестных/двоичных сторонних модулей.

для изменяемых входных параметров:

in my_func(size_t input_param)
{
  char buffer[input_param];
  // or any other initialization of a big object on the stack
  ....
}

Совет:

  • вы должны пометить стек некоторыми магическими номерами (в случае его выделения) и проверить, будут ли изменяться эти магические числа (в этом случае стека будет недостаточно для задачи/потока/процесса и, вероятно, должно быть увеличено )