Почему переполнение стека остается проблемой? - PullRequest
43 голосов
/ 10 июля 2010

Этот вопрос загадывает меня годами, и, учитывая название этого сайта, это место, где можно задать вопрос.

Почему у нас, программистов, есть эта StackOverflow проблема?

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

Я буду говорить в контексте C # / Java, потому что я использую их чаще всего, но это, вероятно, более широкая проблема.

Фиксированный размер стека приводит к огромным проблемам:

  • Невозможно написать рекурсивный алгоритм, если вы абсолютно не уверены, что глубина рекурсии мала. Линейная сложность памяти рекурсивного алгоритма часто недопустима.
  • Дешевого способа создания новых тем не существует. Вы должны выделить огромный блок памяти для стека, чтобы учесть все возможные варианты использования потока.
  • Даже если вы не используете очень глубокую рекурсию, у вас всегда есть риск исчерпания стекового пространства по той причине, что размер стека является произвольным фиксированным числом. Учитывая, что StackOverflow обычно неустраним, на мой взгляд, это большая проблема.

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

Но это еще не так. Зачем? Существуют ли фундаментальные ограничения современных процессоров, которые делают его невозможным / неэффективным? Если вы думаете о снижении производительности, которое навязывает перераспределение, это должно быть приемлемо, потому что люди используют структуры типа ArrayList все время без особых страданий.

Итак, вопрос в том, что я что-то упустил, и StackOverflow не является проблемой, или я что-то упускаю, и есть много языков с динамическим стеком, или есть какая-то серьезная причина для это невозможно / трудно реализовать?

Edit: Некоторые люди говорили, что производительность будет большой проблемой, но учтите это:

  • Мы оставляем скомпилированный код без изменений. Доступ к стеку остается прежним, поэтому производительность в «обычном случае» остается прежней.
  • Мы обрабатываем исключение ЦП, которое происходит, когда код пытается получить доступ к нераспределенной памяти и запускает нашу процедуру «перераспределения». Перераспределения не будут частыми, потому что <поместите ваш обычный аргумент ArrayList здесь>. Должен работать на большинстве процессоров защищенного режима без потери производительности. Нет

Ответы [ 11 ]

0 голосов
/ 10 июля 2010

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

  • Вы могли бы сделать стек похожим на std :: vector объектом, но у вас была бы чрезвычайно непредсказуемая производительность, когда он решил изменить размер - и в любом случае, он, скорее всего, продолжал бы делать это, пока вся куча не будет исчерпана и это еще более раздражает.
  • Вы можете сделать это как std :: list, где он вырос до O (1). Однако арифметика указателей, используемая в статическом стеке, настолько критична во всех отношениях к производительности программы, что она будет бесполезно медленной. Языки были изобретены так, чтобы иметь одно возвращаемое значение и произвольное количество входных параметров, потому что это то, что соответствует статической парадигме стека / указателя.

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

...