Когда вы беспокоитесь о размере стека? - PullRequest
13 голосов
/ 16 декабря 2009

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

Ответы [ 19 ]

2 голосов
/ 16 декабря 2009

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

2 голосов
/ 16 декабря 2009

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

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

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

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

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

(И да, это реальные снафусы.)

1 голос
/ 17 декабря 2009

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

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

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

1 голос
/ 16 декабря 2009

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

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

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

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

1 голос
/ 16 декабря 2009

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

0 голосов
/ 02 сентября 2010

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

  • когда ваша программа аварийно завершает работу - обычно эти ошибки обычно кажутся странными, когда вы впервые видите их:)
  • вы используете алгоритм, который использует рекурсию , а имеет пользовательский ввод в качестве одного из своих параметров (вы не знаете, сколько стека может использовать ваш алгоритм)
  • вы работаете на встроенных платформах (или платформах, где важен каждый ресурс). Обычно на этих платформах стек выделяется до того, как процесс создан, поэтому необходимо правильно оценить требования к стеку
  • вы создаете объекты в стеке в зависимости от некоторых параметров, изменяемых пользовательским вводом (см. Пример ниже)
  • когда код, выполняемый в потоке / процессе / задаче, является очень большим, и существует множество вызовов функций, которые уходят вглубь стека и генерируют огромный стек вызовов. Это обычно происходит в больших инфраструктурах, которые объединяют множество триггеров и обработку событий (среда с графическим интерфейсом; например: 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
  ....
}

Совет:

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

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

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

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

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

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

0 голосов
/ 17 декабря 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...