О выделении стека C / C ++ - PullRequest
       27

О выделении стека C / C ++

5 голосов
/ 26 марта 2009

При изучении C ++ (и C) у меня были некоторые конкретные сомнения относительно работы выделения стека, которые я не могу найти решение:

  1. Вызывает ли выделение стека функции malloc / free неявно? Если не; как он обеспечивает отсутствие конфликта между распределением стека и распределением кучи?

  2. Если да; распределение стека в C ++ тоже неявно вызывает new / delete? Если да; Влияет ли перегрузка нового оператора на класс на распределение его стека?

Это дало запутанные результаты в VC ++; но поскольку VC ++ не полностью соответствует стандартам (или я так слышал), я решил, что лучше спросить здесь ...

Ответы [ 7 ]

24 голосов
/ 26 марта 2009

Распределение стека не использует ничего, кроме malloc / free. Он использует кусок памяти, называемый программным стеком, который является просто непрерывным сегментом памяти.

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

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

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

16 голосов
/ 26 марта 2009

Ответ на ваш первый вопрос - Нет. Стек вообще не выделяется из кучи.

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

6 голосов
/ 26 марта 2009

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

Вы можете передать указатель на память, выделенную alloca () для любой другой функции / метода, которая ожидает указатель. Вы НЕ ДОЛЖНЫ возвращать указатель, выделенный alloca ().

Вот некоторые преимущества и недостатки использования стека.

5 голосов
/ 26 марта 2009

Здесь есть хороший вопрос:

"как это убедиться, что нет конфликт между распределением стека и выделение кучи? "

Практически во всех реализациях C / C ++ существует единое непрерывное адресное пространство, поэтому выделенная память для стека и кучи должна сосуществовать в этом пространстве.

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

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

Итак, очень условно говоря, вы можете думать о стеке как о типе объекта, который сосуществует в куче. Весь стек malloc -одан все за один раз, когда поток запускается, а затем он перераспределяется, а затем он получает free -d за один раз.

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

5 голосов
/ 26 марта 2009

В C и C ++ существует два типа выделения памяти: «автоматический», когда объект создается на время существования вызова функции, и «динамический», когда некоторая память выделяется функцией, предоставляемой средой выполнения.

В подавляющем большинстве реализаций времени выполнения автоматические объекты выделяются с использованием непрерывного стека, предоставляемого операционной системой при создании потока. Стек обычно начинается с высокоценного адреса и уменьшается на размер объекта. Динамическое распределение (malloc в C, новое в C ++) использует некоторую другую память, запрошенную у операционной системы. Поскольку ОС знает об адресах, которые использует стек, она не выделяет эти адреса динамическим запросам. Поскольку динамическая область не упорядочена, ее часто называют кучей.

Таким образом, выделение «стека» не выполняет malloc / free. Автоматические объекты в C ++ вызывают конструктор и деструктор, но не новые или удаляемые, поскольку новые и удаляемые также имеют код для управления динамической памятью.

1 голос
/ 26 марта 2009

Помните, что «распределение стека» - это деталь реализации. Нет гарантии, что стек используется для автоматического хранения. Например, мэйнфреймы IBM не знали (хотя мне говорят, что их более современные машины делают).

1 голос
/ 26 марта 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...