Что и где находится стек и куча? - PullRequest
7640 голосов
/ 17 сентября 2008

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

  • Где и что они (физически в памяти реального компьютера)?
  • В какой степени они контролируются ОС или языком исполнения?
  • Каков их охват?
  • От чего зависит размер каждого из них?
  • Что делает человека быстрее?

Ответы [ 25 ]

108 голосов
/ 17 сентября 2008

Я думаю, что многие другие люди дали вам в основном правильные ответы по этому вопросу.

Одна деталь, которая была упущена, однако, состоит в том, что «куча» на самом деле должна, вероятно, называться «бесплатным магазином». Причина этого различия заключается в том, что исходное бесплатное хранилище было реализовано со структурой данных, известной как «биномиальная куча». По этой причине выделение из ранних реализаций malloc () / free () было выделением из кучи. Однако в наши дни большинство бесплатных магазинов реализованы с очень сложными структурами данных, которые не являются биномиальными кучами.

104 голосов
/ 11 июня 2014

Что такое стек?

Стек - это куча объектов, обычно аккуратно расположенных.

Enter image description here

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

Что такое куча?

Куча - это неопрятная коллекция беспорядочно скопившихся вещей.

Enter image description here

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

Оба вместе

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

Что быстрее - стек или куча? И почему?

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

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

Модель памяти Java

Enter image description here

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

87 голосов
/ 19 марта 2009

Вы можете делать некоторые интересные вещи со стеком. Например, у вас есть такие функции, как alloca (при условии, что вы можете обойти обильные предупреждения относительно его использования), который является формой malloc, которая специально использует стек, а не кучу, для памяти.

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

84 голосов
/ 19 марта 2009

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

Куча - это область памяти, из которой сделаны динамические выделения памяти (явные вызовы «new» или «allocate»). Это специальная структура данных, которая может отслеживать блоки памяти разных размеров и статус их распределения.

В «классических» системах ОЗУ было расположено так, что указатель стека начинался с нижней части памяти, указатель кучи начинался сверху, и они росли друг к другу. Если они перекрываются, у вас недостаточно оперативной памяти. Это не работает с современными многопоточными ОС, хотя. Каждый поток должен иметь свой собственный стек, и они могут создаваться динамически.

79 голосов
/ 02 апреля 2009

Из WikiAnwser.

Stack

Когда функция или метод вызывает другую функцию, которая, в свою очередь, вызывает другую функцию и т. Д., Выполнение всех этих функций остается приостановленным, пока самая последняя функция не вернет свое значение.

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

Стек важно учитывать при обработке исключений и выполнении потоков.

Heap

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

50 голосов
/ 30 января 2014

Stack

  • Очень быстрый доступ
  • Не нужно явно отменять распределение переменных
  • Пространство эффективно управляется процессором, память не фрагментируется
  • Только локальные переменные
  • Ограничение на размер стека (зависит от ОС)
  • Переменные не могут быть изменены

Heap

  • Переменные могут быть доступны глобально
  • Нет ограничений на объем памяти
  • (относительно) медленный доступ
  • Нет гарантированного эффективного использования пространства, со временем память может фрагментироваться при выделении блоков памяти, а затем освобождаться
  • Вы должны управлять памятью (вы отвечаете за распределение и освобождение переменных)
  • Размер переменных можно изменить с помощью realloc ()
42 голосов
/ 18 июля 2017

ОК, просто и в двух словах, они означают заказано и не заказано ...!

Стек : В элементах стека вещи оказываются друг на друге, что означает, что они будут быстрее и эффективнее обрабатываться! ...

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

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

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

enter image description here

39 голосов
/ 02 мая 2016

Короче

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


Подробнее

Стек

Стек представляет собой структуру данных «LIFO» (последний пришел, первый вышел), которая управляется и оптимизируется центральным процессором довольно близко. Каждый раз, когда функция объявляет новую переменную, она «помещается» в стек. Затем каждый раз при выходе из функции все переменные, помещенные в стек этой функцией, освобождаются (то есть они удаляются). После освобождения переменной стека эта область памяти становится доступной для других переменных стека.

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

Больше можно найти здесь .


Куча

Куча - это область памяти вашего компьютера, которая не управляется автоматически для вас и не так жестко управляется процессором. Это более свободно плавающая область памяти (и больше). Чтобы выделить память в куче, вы должны использовать malloc () или calloc (), которые являются встроенными функциями C. После выделения памяти в куче вы несете ответственность за использование free () для освобождения этой памяти, когда она вам больше не нужна.

Если вы не сделаете этого, ваша программа будет иметь то, что известно как утечка памяти. То есть память в куче все равно будет выделена (и не будет доступна другим процессам). Как мы увидим в разделе отладки, есть инструмент под названием Valgrind , который может помочь вам обнаружить утечки памяти.

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

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

Больше можно найти здесь .


Переменные, размещенные в стеке, сохраняются непосредственно в памяти, и доступ к этой памяти очень быстрый, и его распределение решается при компиляции программы. Когда функция или метод вызывает другую функцию, которая в свою очередь вызывает другую функцию и т. Д., Выполнение всех этих функций остается приостановленным до тех пор, пока самая последняя функция не вернет свое значение. Стек всегда резервируется в порядке LIFO, последний зарезервированный блок всегда является следующим блоком, который должен быть освобожден. Это действительно упрощает отслеживание стека, освобождение блока из стека - не более чем настройка одного указателя.

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

Enter image description here

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

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

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

Enter image description here

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

Даже более подробно дано здесь и здесь .


Теперь перейдите к ответам на ваш вопрос .

В какой степени они контролируются ОС или языковой средой выполнения?

ОС выделяет стек для каждого потока системного уровня при создании потока. Обычно ОС вызывается языковой средой выполнения для выделения кучи для приложения.

Больше можно найти здесь .

Каков их объем?

Уже дано сверху.

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

Больше можно найти в здесь .

От чего зависит размер каждого из них?

Размер стека устанавливается OS при создании потока. Размер кучи устанавливается при запуске приложения, но может увеличиваться по мере необходимости (распределитель запрашивает больше памяти у операционной системы).

Что делает человека быстрее?

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

Кроме того, стек против кучи - это не только вопрос производительности; он также многое говорит об ожидаемом времени жизни объектов.

Подробности можно найти по здесь .

35 голосов
/ 27 марта 2015

В 1980-х годах UNIX распространялся как зайчики, когда крупные компании катали свои собственные. У Exxon был такой же, как и утерянные в истории десятки брендов. Распределение памяти было оставлено на усмотрение многих разработчиков.

Типичная программа на С была разложена в памяти возможность увеличения путем изменения значения brk (). Как правило, HEAP была чуть ниже этого значения BRK и увеличение brk увеличило количество доступной кучи.

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

Один типичный блок памяти был BSS (блок нулевых значений) который был случайно не обнулен в предложении одного производителя. Другой был DATA, содержащий инициализированные значения, включая строки и числа. Третьим был код, содержащий CRT (время выполнения C), main, функции и библиотеки.

Появление виртуальной памяти в UNIX меняет многие ограничения. Нет никаких объективных причин, почему эти блоки должны быть смежными, или фиксированного размера, или заказал определенным образом сейчас. Конечно, до UNIX были Multics, которые не страдали от этих ограничений. Вот схема, показывающая один из макетов памяти той эпохи.

A typical 1980s style UNIX C program memory layout

29 голосов
/ 14 сентября 2017

стек , куча и данные каждого процесса в виртуальной памяти:

stack, heap and static data

...