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

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

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

Преимущества и недостатки [ править ]

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

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

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

Системный интерфейс [ править ]

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

В Microsoft Windows существует более безопасная версия allocacalled _malloca, которая сообщает об ошибках. Это требует использования _freea. [5] gnulib предоставляет эквивалентный интерфейс, хотя вместо того, чтобы генерировать исключение SEH при переполнении, он делегирует его mallocпри обнаружении превышения размера. [6] Подобная функция может быть эмулирована с использованием ручного учета и проверки размера, например, при использовании alloca_accountв glibc. [7]

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

Ссылки [ править ]

  1. ^ «Преимущества Alloca» . GNU C Library .
  2. ^ "Встроенный" . Использование коллекции компиляторов GNU (GCC) .
  3. ^ alloca(3)  -  Руководство программиста Linux - Функции библиотеки
  4. ^ "Почему использование alloca () не считается хорошей практикой?" . stackoverflow.com . Проверено 5 января 2016 . CS1 maint: обескураженный параметр ( ссылка )
  5. ^ "_malloca" . Документация Microsoft CRT .
  6. ^ "gnulib / malloca.h" . GitHub . Проверено 24 ноября 2019 . CS1 maint: обескураженный параметр ( ссылка )
  7. ^ "glibc / include / alloca.h" . Зеркала Берена Минора. 23 ноября 2019.

См. Также [ править ]

  • Автоматическая переменная
  • Статическая переменная
  • Стек вызовов
  • Распределение динамической памяти
  • Переполнение буфера стека
  • Штабелеукладчик
  • Переполнение стека