Области выделения памяти в С++ (Stack vs heap vs Static)

Вопрос:Я понимаю, что в С++ есть три, а не две области памяти: стек, куча и область для статических назначенных функций. У меня есть два вопроса. Почему куча намного медленнее, чем стек? Разумеется, это должен быть только один дополнительный уровень косвенности? Является ли область памяти, выделенная для статических "функций" (переменных, функций, классов), обеспечивает более высокую производительность,

Вопрос:

Я понимаю, что в С++ есть три, а не две области памяти: стек, куча и область для статических назначенных функций. У меня есть два вопроса.

  • Почему куча намного медленнее, чем стек? Разумеется, это должен быть только один дополнительный уровень косвенности?

  • Является ли область памяти, выделенная для статических “функций” (переменных, функций, классов), обеспечивает более высокую производительность, чем куча?

Лучший ответ:

Сначала пара боковых нот. Правильная терминология является автоматической, а не стекной, динамической, а не кучей. Другим является то, что с С++ 11 теперь существует четыре, а не три типа памяти. С++ 11 добавляет локальную память потока в микс.

Автоматическая память выполняется быстро, поскольку она реализуется с использованием стека вызовов на большинстве машин. Все, что требуется, – это настроить указатель стека на нужную сумму и вуаля! выделяется память. Динамическая память требует намного больше работы под капотом. Необходимая память может быть не привязана к процессу, и для этого требуется пройти через ОС. Даже если память доступна, инструментам управления динамической памятью все равно придется ее найти и пометить как используемую.

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

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

Ответ №1

1) Почему куча намного медленнее, чем стек? Разумеется, это должен быть только один дополнительный уровень косвенности?

Так как выделение памяти в стеке означает увеличение 1 то указатель стека sp на N, где N – количество байтов. Изменение sp таким образом достаточно быстро. С кучей вы делаете много вещей, например, находить свободный слот или запрашивать ОС для памяти, например, дорогостоящие операции.

1. или уменьшаясь, в зависимости от того, каким образом стек растет!

2) Является ли область памяти, выделенная для статических “функций” (переменные, функции, классы), обеспечивает более высокую производительность, чем куча?

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

Ответ №2

Хотя оператор “куча медленнее” слишком широк, чтобы быть значимым, некоторые аспекты, связанные с распределением кучи, определенно медленнее, чем куча. В отличие от стека, который не может быть фрагментирован, потому что вы не можете удалить вещи из середины стека, куча подвержена фрагментации. Ваша программа может де-распределять объекты в произвольном порядке, создавая “дыры” в куче. Когда вы запрашиваете больше памяти, распределитель должен найти подходящее “отверстие” для выполнения вашего запроса.

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

Что касается хранилища static, он применяется только к элементам данных: статические функции и статические функции-члены просто повторно используют ключевое слово без повторного использования его значения. Объекты в статическом хранилище выделяются только один раз, поэтому нет причин для фрагментации.

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

Ответ №3

При сравнении скорости стека, кучи или статических областей распределения есть две разные скорости для сравнения.

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

Во-вторых, существует скорость выделения. Здесь возникают большие различия.
Статически выделенные объекты получают свою память, зарезервированную при запуске программы (или время загрузки библиотеки, когда они находятся в динамически загружаемой библиотеке), поэтому их время распределения неизмеримо коротко в отношении программы.
Объекты, выделенные стеком, также дешевы для распределения, потому что они берут предсказуемый шаблон распределения (последний выделенный == сначала освобожден), который компилятор может легко принять во внимание. Например, если приложение имеет несколько потоков, оно также будет иметь несколько стеков (каждый стек зарезервирован для одного потока), поэтому потоки не должны конкурировать друг с другом за доступ к памяти стека.
Куча выделенных объектов сложны, потому что куча используется для всего, что не очень хорошо вписывается в ранние группы. Кроме того, для всего приложения обычно имеется только одна куча, поэтому для выделения памяти из кучи требуется синхронизация потоков. И поскольку шаблоны распределения/освобождения довольно случайны, необходимо принять меры, чтобы не потерять слишком много памяти кучи из-за фрагментации кучи. Для этого требуется некоторое время, которое выплачивается при выполнении распределения или освобождения.

Ответ №4

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

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

Ответ №5

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

Оцените статью
Добавить комментарий