Разница между распределением статической памяти и распределением динамической памяти

Ответы:

98

Существует три типа распределения: статическое, автоматическое и динамическое.

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

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

void func() {
    int i; /* `i` only exists during `func` */
}

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

int* func() {
    int* mem = malloc(1024);
    return mem;
}

int* mem = func(); /* still accessible */

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

free(mem);
Константиний
источник
2
Конечно, у вас есть контроль над временем жизни переменных ... вы сами определяете объем, верно?
Лучиан Григоре
Конечно, но я не это имел в виду. Вы не можете продлить время жизни переменных до истечения срока их действия. Но, возможно, мне следует уточнить это в своем ответе. Спасибо
Константиний
5
-1 Это неправильный ответ. Вы путаете статические и автоматические переменные.
brice
2
Ваше собственное предложение гласит: « Статическое размещение означает, что память для ваших переменных выделяется автоматически ». Это неверно . Посмотрите, что написано на странице руководства по GNU libc .
brice
1
@EliBendersky Сейчас это перефразировано. Проверьте, правильно ли это сейчас.
Сурадж Джайн
120

Это стандартный вопрос на собеседовании:

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

Являются ли памяти , выделенные во время выполнения , используя calloc(), malloc()и друзья. Иногда также упоминается как память «кучи», хотя это не имеет ничего общего с кучей структур данных исх .

int * a = malloc(sizeof(int));

Память в куче является постоянной, пока не free()будет вызвана. Другими словами, вы контролируете время жизни переменной.

Автоматическое выделение памяти

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

int a = 43;

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

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

Выделяется во время компиляции * , а время жизни переменной в статической памяти - это время жизни программы .

В C статическая память может быть выделена с помощью staticключевого слова. Область видимости - это только единица компиляции.

Все становится более интересным, когда рассматривается externключевое слово . Когда externпеременная определена, компилятор выделяет для нее память. Когда externпеременная объявляется , компилятор требует, чтобы переменная была определена в другом месте. Неспособность объявить / определить externпеременные вызовет проблемы связывания, в то время как отказ объявить / определить staticпеременные вызовет проблемы компиляции.

в области файла ключевое слово static не является обязательным (вне функции):

int a = 32;

Но не в области действия функции (внутри функции):

static int a = 32;

Технически, externи staticдва отдельных класса переменных в C.

extern int a; /* Declaration */
int a; /* Definition */

* Примечания по распределению статической памяти

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

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

Например, компилятор может создать большой dataраздел в скомпилированном двоичном файле, и когда программа загружается в память, адрес вdataсегмент программы будет использоваться как расположение выделенной памяти. Это имеет заметный недостаток, заключающийся в том, что скомпилированный двоичный файл становится очень большим при использовании большого количества статической памяти. Можно написать двоичный файл размером в несколько гигабайт, созданный менее чем из полдюжины строк кода. Другой вариант - компилятор ввести код инициализации, который будет выделять память другим способом перед выполнением программы. Этот код будет отличаться в зависимости от целевой платформы и ОС. На практике современные компиляторы используют эвристику, чтобы решить, какой из этих вариантов использовать. Вы можете попробовать это сами, написав небольшую программу на C, которая выделяет большой статический массив из 10k, 1m, 10m, 100m, 1G или 10G элементов. Для многих компиляторов размер двоичного файла будет линейно расти вместе с размером массива и после определенной точки,

Регистровая память

Последний класс памяти - это «регистровые» переменные. Как и ожидалось, регистровые переменные должны быть размещены в регистре ЦП, но на самом деле решение остается за компилятором. Вы не можете превратить регистровую переменную в ссылку, используя адрес.

register int meaning = 42;
printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */

Большинство современных компиляторов умнее вас выбирают, какие переменные следует помещать в регистры :)

Ссылки:

брис
источник
3
Примечание: я бы предложил int * a = malloc(sizeof(*a));вместо этого, чтобы не повторять тип a. Это делает вещи намного проще, если когда-либо тип aизменений.
Shahbaz
1
Фактически это называется кучей, но это не имеет ничего общего со структурой данных кучи. Куча в данном случае означает беспорядок
динамический
2
«Распределение статической памяти ... выделяется во время компиляции» Вы имеете в виду, что размер выделения определяется во время компиляции? Разве выделение памяти не происходит только во время выполнения?
lf215
Привет, у меня есть сомнения, если вы все еще отвечаете :(. А как насчет автоматического выделения памяти? Будет ли компилятор также сохранять адреса в разделе данных для этих локальных переменных и передавать их исполняемому файлу. И когда код выполняется (и входит в область видимости) ) эти адреса будут фактически использоваться в качестве местоположений выделенной памяти. Или они фактически выделяются только во время выполнения, без создания и обработки адресов моим компилятором?
LocalHost,
1
@LocalHost Автоматические переменные ограничены временем существования контекста (фигурные скобки), в котором они были определены. это обычно выделяется в стеке вызовов во время выполнения. Это точно не хранится в разделе данных. Вы можете прочитать стандарт C18 здесь: (6.2.4.5-7) web.archive.org/web/20181230041359/http://www.open-std.org/jtc1/…
brice
3

Распределение статической памяти:

  • Переменные распределяются постоянно
  • Распределение выполняется до выполнения программы
  • Он использует структуру данных, называемую стеком, для реализации статического распределения.
  • Менее эффективными
  • Нет возможности повторного использования памяти

Распределение динамической памяти:

  • Переменные выделяются только в том случае, если программный модуль становится активным.
  • Распределение выполняется во время выполнения программы
  • Он использует структуру данных, называемую кучей, для реализации динамического распределения.
  • Более эффективным
  • Есть возможность повторного использования памяти . Память может быть освобождена, когда она не требуется
Vinay
источник
1
«Распределение статической памяти [...] Он использует структуру данных, называемую стеком, для реализации статического распределения» Нет , это неверно и вводит в заблуждение. Пожалуйста, посмотрите мой пост, чтобы узнать о разнице между автоматическим и статическим распределением. Статическая память может использовать стек. Это сильно зависит от реализации, и для одной реализации можно использовать несколько стратегий. Я тоже не уверен, что вы имеете в виду под «менее эффективным». @Trieu Toan, вы изменили значение этого ответа плохим редактированием.
brice
2

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

Динамическое выделение памяти: для динамического получения памяти используются такие функции, как malloc () или calloc (). Если эти функции используются для динамического получения памяти и значения, возвращаемые этими функциями, присваиваются переменным-указателям, такие назначения известны как динамическая память. allocation.memory назначается во время выполнения.

Раджив Кумар
источник
1

Разница между СТАТИЧЕСКИМ РАСПРЕДЕЛЕНИЕМ ПАМЯТИ И ДИНАМИЧЕСКИМ РАСПРЕДЕЛЕНИЕМ ПАМЯТИ

Память выделяется до начала выполнения программы (во время компиляции).
Память выделяется во время выполнения программы.

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

Переменные остаются постоянно распределенными.
Выделяется только при активном программном блоке.

Реализовано с помощью стопок и куч.
Реализовано с использованием сегментов данных.

Указатель необходим для доступа к переменным.
Нет необходимости в динамически выделяемых указателях.

Более быстрое исполнение, чем Dynamic.
Выполнение медленнее, чем статическое.

Больше памяти Требуется больше места.
Требуется меньше места в памяти.

Эбенезер
источник
1
распределение статической памяти выделяется в стеке, а распределение динамической памяти - в куче
Усман Курд
@UsmanKurd Это вообще неверно относительно статической памяти. Смотрите мой ответ.
brice
0

Распределение статической памяти выделяется перед выполнением программы pf во время компиляции. Размещение динамической памяти - это выделенная память во время выполнения программы во время выполнения.

Риту Махешвари
источник
-1

Распределение статической памяти. Выделенная память будет в стеке.

int a[10];

Распределение динамической памяти. Выделенная память будет в куче.

int *a = malloc(sizeof(int) * 10);

и последний должен быть свободен, так как в C. нет сборщика мусора (GC).

free(a);
Onemach
источник