Я хотел бы знать, в чем разница между распределением статической памяти и распределением динамической памяти?
Не могли бы вы объяснить это каким-нибудь примером?
Я хотел бы знать, в чем разница между распределением статической памяти и распределением динамической памяти?
Не могли бы вы объяснить это каким-нибудь примером?
Ответы:
Существует три типа распределения: статическое, автоматическое и динамическое.
Статическое размещение означает, что память для ваших переменных выделяется при запуске программы. Размер фиксируется при создании программы. Он применяется к глобальным переменным, переменным области видимости файла и переменным, квалифицируемым как 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);
Это стандартный вопрос на собеседовании:
Являются ли памяти , выделенные во время выполнения , используя 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. */
Большинство современных компиляторов умнее вас выбирают, какие переменные следует помещать в регистры :)
int * a = malloc(sizeof(*a));
вместо этого, чтобы не повторять тип a
. Это делает вещи намного проще, если когда-либо тип a
изменений.
Распределение статической памяти:
Распределение динамической памяти:
Распределение статической памяти: компилятор выделяет необходимое пространство памяти для объявленной переменной. Используя адрес оператора, получается зарезервированный адрес, и этот адрес может быть назначен переменной-указателю. Поскольку большинство объявленных переменных имеют статическую память, это способ присвоения значения указателя переменной-указателю известен как выделение статической памяти. память назначается во время компиляции.
Динамическое выделение памяти: для динамического получения памяти используются такие функции, как malloc () или calloc (). Если эти функции используются для динамического получения памяти и значения, возвращаемые этими функциями, присваиваются переменным-указателям, такие назначения известны как динамическая память. allocation.memory назначается во время выполнения.
Разница между СТАТИЧЕСКИМ РАСПРЕДЕЛЕНИЕМ ПАМЯТИ И ДИНАМИЧЕСКИМ РАСПРЕДЕЛЕНИЕМ ПАМЯТИ
Память выделяется до начала выполнения программы (во время компиляции).
Память выделяется во время выполнения программы.
Во время выполнения не выполняются действия по выделению или освобождению памяти.
Привязки к памяти устанавливаются и уничтожаются во время выполнения.
Переменные остаются постоянно распределенными.
Выделяется только при активном программном блоке.
Реализовано с помощью стопок и куч.
Реализовано с использованием сегментов данных.
Указатель необходим для доступа к переменным.
Нет необходимости в динамически выделяемых указателях.
Более быстрое исполнение, чем Dynamic.
Выполнение медленнее, чем статическое.
Больше памяти Требуется больше места.
Требуется меньше места в памяти.
Распределение статической памяти выделяется перед выполнением программы pf во время компиляции. Размещение динамической памяти - это выделенная память во время выполнения программы во время выполнения.