Распределение памяти на основе стека

редактировать
Типичный стек, хранящий локальные данные и информацию о вызовах для вызовов вложенных процедур (не обязательно вложенных процедур ). Эта стопка растет вниз от своего источника. Указатель стека указывает на самый верхний элемент данных в стеке. Операция push уменьшает указатель и копирует данные в стек; операция pop копирует данные из стека, а затем увеличивает указатель на единицу. Каждая процедура, вызываемая в программе, сохраняет информацию о возвращении процедуры (желтым цветом) и локальные данные (другими цветами), помещая их в стек.

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

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

Содержание

  • 1 Преимущества и недостатки
  • 2 Системный интерфейс
  • 3 Ссылки
  • 4 См. Также

Преимущества и недостатки

Поскольку данные добавляются и удаляются по принципу «последним вошел - первым ушел», выделение памяти на основе стека очень просто и обычно намного быстрее, чем распределение памяти на основе кучи (также известное как распределение динамической памяти ), обычно выделяемое через malloc. Другая особенность заключается в том, что память в стеке автоматически и очень эффективно освобождается при выходе из функции, что может быть удобно для программиста, если данные больше не требуются. (То же самое относится к longjmp, если он переместился в точку до того, как произошел вызов alloca.) Если, однако, данные необходимо сохранить в какой-либо форме, тогда они должны быть скопированы из стека в кучу до выхода из функции. Следовательно, выделение на основе стека подходит для временных данных или данных, которые больше не требуются после выхода из текущей функции.

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

Распределение на основе стека также может вызвать незначительные проблемы с производительностью: оно приводит к кадрам стека переменного размера, поэтому необходимо управлять как указателями стека , так и указателями кадров (с кадрами стека фиксированного размера, один из них избыточен). Обычно это намного дешевле, чем вызов mallocи free. В частности, если текущая функция содержит оба вызова alloca и блоки, содержащие локальные данные переменной длины, то возникает конфликт между попытками alloca увеличить текущий кадр стека до тех пор, пока текущая функция не завершится, по сравнению с необходимостью компилятора разместить локальные переменные переменной длины в то же место в кадре стека. Этот конфликт обычно разрешается путем создания отдельной цепочки кучи для каждого вызова alloca (см.: https://code.woboq.org/gcc/libiberty/alloca.c.html ). Цепочка записывает глубину стека, на которой происходит каждое выделение, последующие вызовы alloca в любой функции обрезают эту цепочку до текущей глубины стека, чтобы в конечном итоге (но не сразу) освободить любое хранилище в этой цепочке. Вызов alloca с нулевым аргументом также может использоваться для освобождения памяти без выделения дополнительной памяти. Вследствие этого конфликта между alloca и хранилищем локальных переменных использование alloca может быть не более эффективным, чем использование malloc.

Системный интерфейс

Многие Unix-подобные системы, а также Microsoft Windows реализуют функцию allocaдля динамического выделения стековая память аналогична основанной на куче malloc . Компилятор обычно преобразует его во встроенные инструкции, управляющие указателем стека, аналогично тому, как обрабатываются массивы переменной длины. Хотя нет необходимости явно освобождать память, существует риск неопределенного поведения из-за переполнения стека. Эта функция присутствовала в системах Unix еще в 32 / V (1978), но не является частью Standard C или какого-либо стандарта POSIX.

В Microsoft Windows существует более безопасная версия allocaпод названием _malloca, которая сообщает об ошибках. Для этого требуется использование _freea. gnulib предоставляет эквивалентный интерфейс, хотя вместо того, чтобы генерировать исключение SEH при переполнении, он делегирует malloc, когда слишком большой размер обнаружен. Аналогичную функцию можно эмулировать с помощью ручного учета и проверки размера, например, при использовании alloca_accountв glibc.

Некоторые семейства процессоров, такие как x86, имеют специальные инструкции для управления стеком выполняемого в данный момент потока. Другие семейства процессоров, включая PowerPC и MIPS, не имеют явной поддержки стека, но вместо этого полагаются на соглашения и делегируют управление стеком двоичному интерфейсу приложения операционной системы (ABI).

Ссылки

См. Также

Последняя правка сделана 2021-06-09 07:01:26
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте