Was und wo sind der Stapel und der Haufen?

Bücher in Programmiersprachen erklären, dass Werttypen auf dem Stapel erstellt werden und Referenztypen auf dem Heap erstellt werden , ohne zu erklären, was diese beiden Dinge sind. Ich habe keine klare Erklärung dafür gelesen. Ich verstehe was ein Stapel ist. Aber

  • wo und was sind sie (physisch im realen Computerspeicher)?
  • Inwieweit werden sie vom Betriebssystem oder von der Sprache gesteuert?
  • Was ist ihr Volumen?
  • Was bestimmt die Größe von jedem von ihnen?
  • Was macht schneller
7380
17 сент. set mattshane 17 sep . 2008-09-17 07:18 08 um 07:18 Uhr 2008-09-17 07:18
@ 25 Antworten

Ein Stack ist ein Speicher, der als Arbeitsspeicher für einen Ausführungsthread reserviert ist. Wenn eine Funktion aufgerufen wird, wird der Block für lokale Variablen und einige Berechtigungsnachweise oben im Stapel reserviert. Wenn diese Funktion zurückkehrt, wird der Block nicht mehr verwendet und kann beim nächsten Aufruf der Funktion verwendet werden. Der Stack ist immer in der Reihenfolge von LIFO reserviert (der letzte in der ersten Reihenfolge). Der zuletzt reservierte Block ist immer der nächste Block, der freigegeben werden soll. Dies macht es einfacher, den Stapel zu verfolgen. Das Freigeben eines Blocks vom Stapel ist nichts anderes als eine Einstellung für einen einzelnen Zeiger.

Ein Heap ist ein Speicher, der für die dynamische Zuordnung reserviert ist. Im Gegensatz zum Stack gibt es keine erzwungene Vorlage zum Zuordnen und Freigeben von Blöcken von einem Heap; Sie können jederzeit einen Block auswählen und jederzeit freigeben. Dies macht es sehr schwierig zu verfolgen, welche Teile des Heaps zu einem bestimmten Zeitpunkt verteilt oder freigegeben werden. Es gibt viele benutzerdefinierte Cum-Verteiler zum Anpassen der Heap-Leistung für verschiedene Verwendungsmuster.

Jeder Thread erhält einen Stapel, während für eine Anwendung normalerweise nur ein Heap verwendet wird (obwohl es nicht ungewöhnlich ist, dass mehrere Heaps für verschiedene Arten der Platzierung vorhanden sind).

Um Ihre Fragen direkt zu beantworten:

Inwieweit werden sie vom Betriebssystem oder von der Sprache gesteuert?

Das Betriebssystem weist für jeden Thread auf Systemebene einen Stapel zu, wenn ein Thread erstellt wird. Normalerweise wird das Betriebssystem von der Sprachausführungsumgebung aufgerufen, um einen Heapspeicher für eine Anwendung zuzuweisen.

Was ist ihr Volumen?

Der Stapel wird an den Faden angehängt. Wenn der Faden aus dem Stapel kommt, wird er korrigiert. Ein Heap wird normalerweise zugewiesen, wenn die Anwendung zur Laufzeit gestartet wird und nach dem Beenden der Anwendung (technischer Prozess) zurückgegeben wird.

Was bestimmt die Größe von jedem von ihnen?

Die Stapelgröße wird beim Erstellen eines Threads festgelegt. Die Größe des Heapspeichers wird beim Start der Anwendung festgelegt, kann sich jedoch bei Bedarf erhöhen (der Allokator fordert mehr Speicher vom Betriebssystem an).

Was macht schneller

Der Stack ist schneller, da das Zugriffsmuster die Zuordnung und den Speicher von Arbeitsspeicher trivial macht (der Zeiger / die Ganzzahl vergrößert oder verkleinert sich) und der Heap hat viel kompliziertere Finanzausweise in Bezug auf die Zuordnung oder Freigabe. Darüber hinaus wird jedes Byte im Stack häufig wiederverwendet, was bedeutet, dass es im Cache des Prozessors angezeigt wird, was es sehr schnell macht. Ein weiterer Heap-Performance-Hit besteht darin, dass der Heap, der hauptsächlich eine globale Ressource ist, typischerweise mehrstufig sein sollte, d. H. Jede Distribution und Veröffentlichung sollte - in der Regel - mit "allen" anderen Heap-Aufrufen im Programm synchronisiert werden.

Eindeutige Demonstration: 2019

5436
17 сент. Die Antwort wird Jeff Hill 17 Sep gegeben. 2008-09-17 07:52 08 um 07:52 Uhr 2008-09-17 07:52

Stack

  • Im RAM des Computers als Bündel gespeichert.
  • Auf dem Stapel erstellte Variablen gehen aus dem Gültigkeitsbereich heraus und werden automatisch freigegeben.
  • Viel schneller zuzuordnen im Vergleich zu Variablen im Heap.
  • Implementiert mit tatsächlicher Stack-Datenstruktur.
  • Speichert lokale Daten und gibt Adressen zurück, die zum Übergeben von Parametern verwendet werden.
  • Kann zu einem Stapelüberlauf führen, wenn zu viel Stapel verwendet wird (meistens von unendlicher oder zu tiefer Rekursion, sehr große Verteilungen).
  • Auf dem Stack erstellte Daten können ohne Zeiger verwendet werden.
  • Sie würden den Stack verwenden, wenn Sie genau wüssten, wie viele Daten Sie vor dem Kompilieren zuordnen müssen, und es ist nicht zu groß.
  • Normalerweise wird die maximale Größe bereits beim Start Ihres Programms festgelegt.

Heap:

border=0
  • Wird im Arbeitsspeicher des Computers genauso gespeichert wie der Stapel.
  • In C ++ müssen Variablen im Heap manuell zerstört werden und fallen niemals aus dem Bereich. Daten werden mit delete , delete[] oder free freigegeben.
  • Die Zuweisung ist >
  • Wird bei Bedarf verwendet, um einen Datenblock für das Programm zuzuweisen.
  • Bei vielen Zuweisungen und Ausnahmen kann eine Fragmentierung auftreten.
  • In C ++ oder C werden die auf dem Heap erstellten Daten durch Zeiger angezeigt und new bzw. malloc .
  • Es kann ein Fehler beim Verteilen auftreten, wenn zu viel Puffer benötigt wird.
  • Sie würden eine Menge verwenden, wenn Sie nicht genau wissen, wie viele Daten Sie zur Laufzeit benötigen, oder wenn Sie viele Daten zuordnen müssen.
  • Verantwortlich für Speicherleck.

Beispiel:

2164
17 сент. Die Antwort wird von Brian R. Bondy 17 Sep gegeben. 2008-09-17 07:20 08 um 07:20 2008-09-17 07:20

Der wichtigste Punkt ist, dass Heap und Stack allgemeine Begriffe für Speicherzuordnungsmethoden sind. Sie können auf verschiedene Arten implementiert werden, und diese Begriffe gelten für grundlegende Konzepte.

  • In dem Stapel von Elementen werden Elemente in der Reihenfolge, in der sie dort platziert wurden, übereinander platziert, und Sie können nur den oberen Teil entfernen (ohne das Ganze zu kippen).

    2019

1294
19 марта '09 в 17:38 2009-03-19 17:38 Die Antwort gibt thomasrutter 19. März 09 um 17:38 2009-03-19 17:38

(Ich habe diese Antwort von einer anderen Frage abgelenkt, die mehr oder weniger von ihr betrogen wurde.)

Die Antwort auf Ihre Frage ist implementierungsspezifisch und kann je nach Compiler und Prozessorarchitektur variieren. Dies ist jedoch eine vereinfachte Erklärung.

  • Sowohl der Stack als auch der Heap sind Speicherbereiche, die vom Basisbetriebssystem zugewiesen werden (häufig virtueller Speicher, der bei Bedarf dem physischen Speicher zugeordnet wird).
  • In einer Umgebung mit mehreren Threads verfügt jeder Thread über einen eigenen, vollständig unabhängigen Stack, der jedoch den Heap aufteilt. Der parallele Zugriff muss auf dem Heap gesteuert werden und ist auf dem Stack nicht möglich.

Ein Haufen

  • Der Heap enthält eine verknüpfte Liste der verwendeten und freien Blöcke. Neue Heap-Zuordnungen ( new oder malloc ) werden erfüllt, indem aus einem der freien Blöcke ein geeigneter Block erstellt wird. Dazu muss die Liste der Blöcke auf dem Heap aktualisiert werden. Diese Metainformationen über Blöcke in einem Heap werden auch in einem Heap gespeichert, häufig in einem kleinen Bereich unmittelbar vor jedem Block.
  • Wenn der Heap wächst, werden neue Blöcke häufig von niedrigeren Adressen zu höheren Adressen zugewiesen. So können Sie sich einen Haufen als einen Haufen Speicherblöcke vorstellen, die mit der Zuweisung von Speicherplatz an Größe zunehmen. Wenn der Heap zu klein ist, um verteilt zu werden, kann die Größe häufig erhöht werden, indem mehr Speicher vom zugrunde liegenden Betriebssystem erworben wird.
  • Das Zuordnen und Freigeben vieler kleiner Blöcke kann einen Stapel in einem Zustand hinterlassen, in dem sich viele kleine freie Blöcke zwischen den verwendeten Blöcken befinden. Eine Anforderung zum Zuweisen eines großen Blocks kann fehlschlagen, da keiner der freien Blöcke groß genug ist, um die Verteilungsanforderung zu erfüllen, selbst wenn die kombinierte Größe der freien Blöcke groß genug ist. Dies wird als Haufenfragmentierung bezeichnet.
  • Wenn ein gebrauchter Block neben einem freien Block freigegeben wird, kann ein neuer freier Block mit einem benachbarten freien Block kombiniert werden, um einen größeren freien Block zu erstellen, der die Heap-Fragmentierung effektiv reduziert.

2019

681
31 июля '09 в 18:54 2009-07-31 18:54 Die Antwort wird von Martin Liversage am 31. Juli 09 um 18:54 Uhr 2009-07-31 18:54 gegeben

Im folgenden Code C #

370
ответ дан Snowcrash 09 нояб. '12 в 15:28 2012-11-09 15:28

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

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

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

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

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

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

Физическое расположение в памяти Это менее актуально, чем вы думаете из-за технологии Virtual Memory , которая заставляет вашу программу думать, что у вас есть доступ к определенному адресу, где физические данные где-то еще (даже на жестком диске!). Адреса, которые вы получаете для стека, растут по мере того, как ваше дерево вызовов становится глубже. Адреса для кучи являются непредсказуемыми (например, специфическими) и, откровенно говоря, не важными.

194
ответ дан Tom Leys 17 сент. '08 в 7:27 2008-09-17 07:27

Чтобы уточнить, этот ответ содержит неверную информацию ( thomas зафиксировал свой ответ после комментариев, круто:)). Другие ответы просто не позволяют объяснить, что означает статическое распределение. Поэтому я объясню три основные формы распределения и то, как они обычно относятся к сегменту кучи, стека и данных ниже. Я также покажу несколько примеров как на C/С++, так и на Python, чтобы помочь людям понять.

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

Однако обычно лучше рассмотреть " область " и " продолжительность жизни ", а не "стек" и "куча".

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

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

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

Я приведу несколько простых аннотированных C-кодов, чтобы проиллюстрировать все это. Лучший способ узнать - запустить программу под отладчиком и посмотреть поведение. Если вы предпочитаете читать python, пропустите до конца ответа:)

Обратите внимание, что добавление ключевого слова "статический" в вышеприведенное объявление предотвращает глобальную область видимости var2. Тем не менее глобальный var1 имеет статическое распределение. Это не интуитивно! По этой причине я стараюсь никогда не использовать слово "статический" при описании области, а вместо этого говорить что-то вроде "файла" или "ограниченного файла". Однако многие люди используют фразу "статическая" или "статическая область" для описания переменной, доступ к которой возможен только из одного файла кода. В контексте времени жизни "статический" всегда означает, что переменная выделяется при запуске программы и освобождается при выходе из программы.

Некоторые люди думают об этих понятиях как о C/С++. Они не. Например, приведенный ниже пример Python иллюстрирует все три типа распределения (возможны некоторые тонкие различия в интерпретируемых языках, в которые я не буду входить).

174
ответ дан davec 11 нояб. '12 в 2:03 2012-11-11 02:03

Другие ответили на широкие штрихи довольно хорошо, поэтому я напишу несколько деталей.

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

  • В C вы можете получить преимущество распределения переменной длины с помощью alloca , который выделяется в стеке, в отличие от alloc, который выделяется в куче. Эта память не сможет выдержать ваш оператор return, но он полезен для буфера с нуля.

  • Создание огромного временного буфера в Windows, в котором вы не используете большую часть, не является бесплатным. Это связано с тем, что компилятор будет генерировать петлю зонда стека, которая вызывается каждый раз, когда будет введена ваша функция, чтобы убедиться, что стек существует (поскольку Windows использует одну страницу защиты в конце вашего стека, чтобы определить, когда нужно наращивать стек. Если вы получите доступ к памяти более одной страницы с конца стека, вы сработаете). Beispiel:

159
ответ дан Don Neufeld 17 сент. '08 в 7:48 2008-09-17 07:48

Другие ответили на ваш вопрос напрямую, но, пытаясь понять стек и кучу, я думаю, что полезно рассмотреть макет памяти традиционного процесса UNIX (без потоков и mmap() -распределителей). На веб-странице "Глоссарий управления памятью" есть схема этого макета памяти.

Стек и куча традиционно расположены на противоположных концах виртуального адресного пространства процесса. Стек автоматически растет при доступе к размеру, заданному ядром (который можно настроить с помощью setrlimit(RLIMIT_STACK, ...) ). Куча растет, когда распределитель памяти вызывает системный вызов brk() или sbrk() , отображая больше страниц физической памяти в виртуальное адресное пространство процесса.

В системах без виртуальной памяти, таких как некоторые встроенные системы, часто применяется тот же базовый макет, за исключением того, что стек и куча фиксированы по размеру. Однако в других встроенных системах (например, на микроконтроллерах Microchip PIC) программный стек представляет собой отдельный блок памяти, который не адресуется инструкциями по перемещению данных и может быть изменен или изменен только с помощью инструкций потока программы (вызов, возврат и т.д.). Другие архитектуры, такие как процессоры Intel Itanium, имеют несколько стеков . В этом смысле стек является элементом архитектуры ЦП.

128
ответ дан bk1e 17 сент. '08 в 10:16 2008-09-17 10:16

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

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

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

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

108
ответ дан Daniel Papasian 17 сент. '08 в 7:29 2008-09-17 07:29

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

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

107
ответ дан Heath 17 сент. '08 в 7:57 2008-09-17 07:57

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

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

2019

ответ дан Shreyos Adikari 11 июня '14 в 22:42 2014-06-11 22:42

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

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

88
ответ дан Peter 19 марта '09 в 18:55 2009-03-19 18:55

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

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

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

85
ответ дан TED 19 марта '09 в 18:13 2009-03-19 18:13

Из WikiAnwser.

Stack

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

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

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

Heap

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

79
ответ дан devXen 02 апр. '09 в 4:25 2009-04-02 04:25

Stack

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

Heap

  • Доступны переменные во всем мире
  • Ограничение размера памяти
  • (Относительно) медленный доступ
  • Нет гарантированного эффективного использования пространства, память может со временем фрагментироваться, когда выделяются блоки памяти, а затем освобождается
  • Вы должны управлять памятью (вы отвечаете за выделение и освобождение переменных)
  • Переменные могут быть изменены с помощью realloc()
50
ответ дан unknown 30 янв. '14 в 9:33 2014-01-30 09:33

Хорошо, просто и вкратце, они означают упорядоченные и не упорядоченные ...!

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

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

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

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

2019

ответ дан Alireza 18 июля '17 в 18:04 2017-07-18 18:04

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

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

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

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

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

2019

35
ответ дан jlettvin 27 марта '15 в 22:55 2015-03-27 22:55

Короче

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


В деталях

Стек

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

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

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


Куча

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

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

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

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

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


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

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

2019

ответ дан Abrar Jahin 02 мая '16 в 15:16 2016-05-02 15:16
  • Введение

Физическая память - это диапазон физических адресов ячеек памяти, в которых приложение или система сохраняет свои данные, код и т.д. Во время выполнения. Управление памятью означает управление этими физическими адресами путем замены данных из физической памяти на запоминающее устройство, а затем обратно в физическую память при необходимости. ОС реализует службы управления памятью с использованием виртуальной памяти. В качестве разработчика приложений на С# вам не нужно писать какие-либо службы управления памятью. CLR использует базовые службы управления памятью ОС, чтобы предоставить модель памяти для С# или любого другого высокоуровневого языка, ориентированного на CLR.

На рисунке 4-1 показана физическая память, которая была абстрагирована и управляется ОС, используя концепцию виртуальной памяти. Виртуальная память - это абстрактный вид физической памяти, управляемый ОС. Виртуальная память - это просто серия виртуальных адресов, и эти виртуальные адреса преобразуются ЦП в физический адрес, когда это необходимо.

Рисунок 4-1. Запоминание памяти CLR

2019

29
ответ дан kokabi 10 нояб. '14 в 20:22 2014-11-10 20:22

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

24
ответ дан Yousha Aleayoub 14 сент. '17 в 20:32 2017-09-14 20:32

Пару центов: я думаю, будет хорошо рисовать память графически и проще:

2019

ответ дан Maxim Akristiniy 17 дек. '15 в 18:08 2015-12-17 18:08

Так как некоторые ответы поменялись, я собираюсь внести свой вклад.

Удивительно, но никто не упомянул, что множественные (т.е. не связанные с количеством запущенных потоков уровня ОС Windows) встречаются не только на экзотических языках (PostScript) или платформах (Intel Itanium), но и в волокна , зеленые темы и некоторые реализации сопрограммы .

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

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

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

Обратите внимание, что я сказал: "Обычно есть отдельный стек для каждой функции". Существуют как стековые, так и стековые реализации курок. Наиболее заметными стековыми реализациями С++ являются Boost.Coroutine и Microsoft PPL async/await . (Тем не менее, С++ возобновляемые функции (ака " async и await " ), которые были предложены С++ 17, скорее всего для использования стекированных сопрограмм.)

Предложено предложение волокон в стандартной библиотеке С++. Кроме того, есть сторонние библиотеки . Зеленые темы чрезвычайно популярны в таких языках, как Python и Ruby.

21
ответ дан shakurov 02 марта '15 в 4:29 2015-03-02 04:29

Мне есть чем поделиться, хотя основные моменты уже освещены.

стек

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

отвал

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

Интересная заметка:

  • Если бы вызовы функций были сохранены в куче, это привело бы к двум беспорядочным точкам:
    1. Благодаря последовательному хранению в стеке выполнение выполняется быстрее. Хранение в куче привело бы к огромному расходу времени, что замедлило бы выполнение всей программы.
    2. Если бы функции хранились в куче (грязное хранилище, на которое указывает указатель), не было бы никакого способа вернуться назад к адресу вызывающей стороны (какой стек дает из-за последовательного хранения в памяти).
9
ответ дан Pankaj Kumar Thapa 15 нояб. '17 в 21:27 2017-11-15 21:27

Многие ответы правильны, как понятия, но мы должны отметить, что стек необходим аппаратным (то есть микропроцессором), чтобы разрешать вызовы подпрограмм (CALL на языке ассемблера..). (Ребята из ООП будут называть это методами)

В стеке вы сохраняете обратные адреса и вызываете → push/ret → pop управляется непосредственно на аппаратном обеспечении.

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

  • Без стека нет может работать микропроцессор. (мы не можем представить себе программу, даже на языке ассемблера, без подпрограмм/функций)
  • Без кучи он может. (Программа ассемблерной программы может работать без нее, поскольку куча представляет собой концепцию ОС, как malloc, то есть вызов OS/Lib.

Использование стека выполняется быстрее:

  • Это аппаратное обеспечение, и даже push/pop очень эффективны.
  • malloc требует входа в режим ядра, используйте lock/semaphore (или другие примитивы синхронизации), выполняющие некоторый код и управляющие некоторыми структурами, необходимыми для отслеживания выделения.
9
ответ дан ingconti 28 июля '17 в 1:14 2017-07-28 01:14

Другие вопросы по меткам > или Задайте вопрос