Что происходит, когда стек и куча сталкиваются - PullRequest
54 голосов
/ 26 августа 2009

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

Заранее спасибо.

Ответы [ 6 ]

61 голосов
/ 26 августа 2009

В современных языках, работающих в современной ОС, вы получите либо переполнение стека (ура!), Либо malloc(), либо sbrk(), либо mmap() не удастся при попытке увеличить кучу. Но не все программное обеспечение современно, поэтому давайте посмотрим на режимы отказа:

  • Если стек растет в кучу, обычно компилятор C начинает молча перезаписывать структуры данных кучи. В современной ОС будет одна или несколько виртуальных памяти защитных страниц , которые не позволяют стеку расти бесконечно. До тех пор, пока объем памяти на страницах защиты не меньше, чем размер записи активации растущей процедуры, ОС гарантирует вам ошибку. Если вы работаете в DOS на машине без MMU, то, вероятно, вы подключены.

  • Если куча врастает в стек, операционная система всегда должна знать о ситуации, и какой-то системный вызов не будет выполнен. Реализация malloc() почти наверняка замечает сбой и возвращает NULL. Что произойдет после этого, зависит от вас.

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

42 голосов
/ 26 августа 2009

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

Имейте в виду, что идея кучи, растущей вверх, и стека, растущего вниз, является только концептуальной. В очень маленьких системах (например, в старых 8-битных микросхемах с CP / M), а также в некоторых PIC и других системах с плоской памятью (без MMU или какой-либо другой поддержки виртуальной или защищенной памяти) куча и стек могут быть реализован таким образом. В этом случае поведение будет неопределенным ... но почти наверняка произойдет сбой, как только код попытается вернуться к какому-либо адресу в верхней части поврежденного стека или следовать косвенному указателю из одной части кучи в другую или. ..

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

12 голосов
/ 26 августа 2009

В такие времена пора обратиться к мудрым словам доктора Эгона Шпенглера ...

  • Dr. Эгон Шпенглер: Есть кое-что очень важное, что я забыл тебе сказать.
  • Dr. Питер Венкман: ​​Что?
  • Dr. Эгон Шпенглер: Не позволяйте куче сталкиваться со стеком.
  • Dr. Питер Венкман: ​​Почему?
  • Dr. Эгон Шпенглер: Это было бы плохо.
  • Dr. Питер Венкман: ​​Я немного неясен в отношении всех «хорошо / плохо». Что значит "плохой"?
  • Dr. Эгон Шпенглер: Попытайтесь представить всю жизнь такой, какой вы ее знаете, мгновенно останавливаясь, и каждая молекула в вашем теле взрывается со скоростью света.
  • Dr. Рэй Станц: Полное обращение с протонами!
  • Dr. Питер Венкман: ​​Это плохо. Хорошо. Хорошо, важный совет по безопасности. Спасибо, Эгон.
6 голосов
/ 26 августа 2009

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

Наконец, вселенная может расколоться.

1 голос
/ 28 июня 2015

Вы получите ошибку сегментации или ошибку выделения памяти, если произойдет переполнение стека / кучи. Вот пример:

void recursiveFun ()
{
    static int i;
//  char *str= (char *)malloc (100);
    printf ("%d\t", i++);
    recursiveFun ();
// free (str);
}

Предположим, вы вызываете вышеуказанную функцию, она выйдет из стека и программа вылетит. Теперь, удалите закомментированные строки и снова вызовите функцию, вы обнаружите, что ошибка сегментации происходит за меньшее время и меньше рекурсии, чем в более ранней версии. [В моей тестовой среде переполнение стека произошло после рекурсии 5237765 в первом случае, тогда как во втором сценарии это произошло после рекурсии 2616325.]

0 голосов
/ 18 сентября 2018

Это даст ошибку переполнения стека. В противном случае произойдет сбой новых функций выделения памяти в куче, таких как malloc ().

...