~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ 20251469E1E8D90A5494739EF1639415__1715928360 ✰
Заголовок документа оригинал.:
✰ Stack overflow - Wikipedia ✰
Заголовок документа перевод.:
✰ Переполнение стека — Википедия ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/Stack_overflow ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/20/15/20251469e1e8d90a5494739ef1639415.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/20/15/20251469e1e8d90a5494739ef1639415__translat.html ✰
Дата и время сохранения документа:
✰ 16.06.2024 09:30:03 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 17 May 2024, at 09:46 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Arc.Ask3.ru: далее начало оригинального документа

Переполнение стека — Википедия Jump to content

Переполнение стека

Из Википедии, бесплатной энциклопедии

В программном обеспечении переполнение стека происходит, если указатель стека вызовов превышает границу стека . Стек вызовов может состоять из ограниченного объема адресного пространства , часто определяемого в начале программы. Размер стека вызовов зависит от многих факторов, включая язык программирования, архитектуру машины, многопоточность и объем доступной памяти. Когда программа пытается использовать больше места, чем доступно в стеке вызовов (то есть, когда она пытается получить доступ к памяти за пределами стека вызовов, что по сути является переполнением буфера ), говорят, что стек переполняется , что обычно приводит к ошибке программы сбой . [1]

Причины [ править ]

Бесконечная рекурсия [ править ]

Наиболее распространенной причиной переполнения стека является чрезмерно глубокая или бесконечная рекурсия, при которой функция вызывает себя так много раз, что пространство, необходимое для хранения переменных и информации, связанной с каждым вызовом, превышает размер стека. [2]

Пример бесконечной рекурсии C. в

int   foo  ()  
 { 
      return   foo  (); 
  } 

Функция foo при ее вызове продолжает вызывать саму себя, каждый раз выделяя дополнительное пространство в стеке, пока стек не переполнится, что приведет к ошибке сегментации . [2] Однако некоторые компиляторы реализуют оптимизацию хвостовых вызовов , позволяющую осуществлять бесконечную рекурсию определенного вида — хвостовую рекурсию — без переполнения стека. Это работает, поскольку вызовы хвостовой рекурсии не занимают дополнительного места в стеке. [3]

Некоторые параметры компилятора C позволяют эффективно оптимизировать хвостовой вызов ; например, скомпилировав приведенную выше простую программу с использованием gcc с -O1 приведет к ошибке сегментации, но не при использовании -O2 или -O3, поскольку эти уровни оптимизации предполагают -foptimize-sibling-calls вариант компилятора. [4] Другие языки, такие как Scheme , требуют, чтобы все реализации включали хвостовую рекурсию как часть стандарта языка. [5]

Очень глубокая рекурсия [ править ]

Рекурсивную функцию, которая теоретически завершается, но на практике вызывает переполнение буфера стека вызовов, можно исправить, превратив рекурсию в цикл и сохранив аргументы функции в явном стеке (вместо неявного использования стека вызовов). Это всегда возможно, поскольку класс примитивно-рекурсивных функций эквивалентен классу LOOP-вычислимых функций. Рассмотрим этот пример в C++ псевдокоде, подобном :

void   function   (  аргумент  )  
 { 
   if   (  условие  ) 
     функция   (  аргумент  .  next  ); 

  } 
куча  .   нажать  (  аргумент  ); 
  в то время как   (  !  стек  .  пустой  ()) 
 { 
   аргумент   =   стек  .   поп  (); 
    если   (  условие  ) 
     стек  .   нажать  (  аргумент  .  следующий  ); 
  } 

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

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

int   pow  (  int   base  ,   int   exp  )   { 
     if   (  exp   >   0  ) 
         return   base   *   pow  (  base  ,   exp   -   1  ); 
      иначе 
         вернуть   1  ; 
  } 
int   pow  (  int   base  ,   int   exp  )   { 
     return   pow_accum  (  base  ,   exp  ,   1  ); 
  } 

 int   pow_accum  (  int   base  ,   int   exp  ,   int   accum  )   { 
     if   (  exp   >   0  ) 
         return   pow_accum  (  base  ,   exp   -   1  ,   accum   *   base  ); 
      иначе 
         вернуть   ток  ; 
  } 

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

pow  (  5  ,   4  ) 
 5   *   pow  (  5  ,   3  ) 
 5   *   (  5   *   pow  (  5  ,   2  )) 
 5   *   (  5   *   (  5   *   pow  (  5  ,   1  ))) 
 5   *   (  5   *   (  5   *   (  5   *   pow  (  5  ,   0  )))) 
 5   *   (  5   *   (  5   *   (  5   *   1  ))) 
 625 
pow  (  5  ,   4  ) 
 pow_accum  (  5  ,   4  ,   1  ) 
 pow_accum  (  5  ,   3  ,   5  ) 
 pow_accum  (  5  ,   2  ,   25  ) 
 pow_accum  (  5  ,   1  ,   125  ) 
 pow_accum  (  5  ,   0  ,   625  ) 
 625 

Обратите внимание, что функция слева должна хранить в своем стеке expколичество целых чисел, которое будет умножено, когда рекурсия завершится и функция вернет 1. Напротив, функция справа должна хранить только 3 целых числа в любой момент времени и вычисляет промежуточный результат, который передается ее следующему вызову. Поскольку никакая другая информация, кроме текущего вызова функции, храниться не должна, оптимизатор хвостовой рекурсии может «отбросить» предыдущие кадры стека, исключая возможность переполнения стека.

Очень большие переменные стека [ править ]

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

Пример очень большой переменной стека в C :

int   foo  ()  
 { 
      двойной   х  [  1048576  ]; 
  } 

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

Переполнение стека усугубляется всем, что уменьшает эффективный размер стека данной программы. Например, одна и та же программа, запущенная без нескольких потоков, может работать нормально, но как только многопоточность будет включена, программа выйдет из строя. Это связано с тем, что большинство программ с потоками имеют меньше места в стеке на поток, чем программы без поддержки потоков. Поскольку ядра, как правило, являются многопоточными, людям, плохо знакомым с разработкой ядра , обычно не рекомендуется использовать рекурсивные алгоритмы или большие буферы стека. [7]

См. также [ править ]

Ссылки [ править ]

  1. ^ Берли, Джеймс Крейг (1 июня 1991 г.). «Использование и портирование GNU Fortran» . Архивировано из оригинала 6 февраля 2012 г.
  2. ^ Перейти обратно: а б В чем разница между ошибкой сегментации и переполнением стека? Архивировано 13 сентября 2021 г. на Wayback Machine в Stack Overflow.
  3. ^ «Введение в схему и ее реализация» . 19 февраля 1997 г. Архивировано из оригинала 10 августа 2007 г.
  4. ^ «Использование коллекции компиляторов GNU (GCC): параметры оптимизации» . Архивировано из оригинала 20 августа 2017 г. Проверено 20 августа 2017 г.
  5. ^ Ричард Келси; Уильям Клингер; Джонатан Рис; и другие. (август 1998 г.). «Пересмотренный 5 Отчет об алгоритмической языковой схеме» . Вычисления высшего порядка и символические вычисления . 11 (1): 7–105. doi : 10.1023/A:1010051815785 . S2CID   14069423. из Архивировано оригинала 05 января 2007 г. Проверено 8 января 2012 г. -09 .
  6. ^ Фельдман, Ховард (23 ноября 2005 г.). «Современное управление памятью, часть 2» . Архивировано из оригинала 20 сентября 2012 г. Проверено 14 августа 2007 г.
  7. ^ «Руководство по программированию ядра: советы по производительности и стабильности» . Apple Inc. 2 мая 2014 г. Архивировано из оригинала 3 мая 2014 г. Проверено 2 мая 2014 г.

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: 20251469E1E8D90A5494739EF1639415__1715928360
URL1:https://en.wikipedia.org/wiki/Stack_overflow
Заголовок, (Title) документа по адресу, URL1:
Stack overflow - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)