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

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

Не могли бы вы объяснить это с помощью любого примера?

 

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

  **Статическое размещение** означает, что память для ваших переменных выделяется при запуске программы. Размер фиксируется при создании программы. Он применяется к глобальным переменным, переменным области видимости файла и переменным, соответствующим `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()` и друзей. Иногда ее также называют "кучной" памятью, хотя она не имеет ничего общего со структурой данных кучи [ref](https://www.quora.com/Why-is-dynamic-memory-allocation-called-heap-memory-allocation "ref").

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

```

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

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

Это то, что обычно называют стековой памятью, и выделяется при вводе новой области (обычно, когда новая функция помещается в стек вызовов). Когда вы выходите из области видимости, значения автоматических адресов памяти не определяются, и доступ к ним является [ошибкой](/questions/2383/can-a-local-variables-memory-be-accessed-outside-its-scope/25570#25570).

```
int a = 43;

```

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

Статическое распределение памяти
--------------------------------

Распределяется во время компиляции *, а время жизни переменной в статической памяти - это [время жизни программы](https://en.wikipedia.org/wiki/Static_variable).

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

Все становится интереснее [, когда ключевое слово `extern` считается](https://en.wikipedia.org/wiki/Extern_variable). Когда переменная `extern` определена, компилятор выделяет для нее память. Когда объявляется переменная `extern`, компилятор требует, чтобы переменная была определена в другом месте. Неспособность объявить/определить переменные `extern` вызовет проблемы с компоновкой, а не объявить/определить переменные `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'. Как и ожидалось, переменные регистра должны быть размещены в регистре процессора, но решение фактически остается за компилятором. Вы не можете превратить переменную регистра в ссылку, используя address-of.

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

```

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

Ссылки:
-------

* [Руководство по libc](https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-and-C.html)
* K & R [Язык программирования C](http://cm.bell-labs.com/cm/cs/cbook/), Приложение A, Раздел 4.1, "Класс хранения". ([PDF](http://net.pku.edu.cn/~course/cs101/2008/resource/The_C_Programming_Language.pdf))
* [Стандарт C11](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf), раздел 5.1.2, 6.2.2.3
* В Википедии также есть хорошие страницы по [статическому выделению памяти](https://en.wikipedia.org/wiki/Static_memory_allocation), [динамическому выделению памяти](https://en.wikipedia.org/wiki/Dynamic_memory_allocation#Dynamic_memory_allocation) и [автоматическому выделению памяти](https://en.wikipedia.org/wiki/Automatic_memory_allocation)
* [Страница динамического выделения памяти C](https://en.wikipedia.org/wiki/C_dynamic_memory_allocation) в Википедии
* Этот [Справочник по управлению памятью](http://www.memorymanagement.org/index.html) содержит больше подробностей о базовых реализациях для динамических распределителей.



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

* Переменные распределяются **навсегда**
* Распределение выполняется **до** выполнения программы
* Он использует структуру данных под названием **stack** для реализации статического размещения
* Менее эффективный
* **нет возможности повторного использования памяти**

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

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



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

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

 

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

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

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

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

Привязывание памяти установлено и уничтожается во время выполнения.

Переменные остаются постоянно выделенными.   

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

Реализовано с использованием стеков и кучек.   

Реализовано с использованием сегментов данных.

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

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

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

Более медленное выполнение, чем статическое.

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

 

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

 

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

```
int a[10];

```

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

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

```

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

```
free(a);

```
 

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

 

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

  **Динамическая память:**. Динамические запоминающие устройства представляют собой полупроводниковые запоминающие устройства, в которых сохраненные данные не будут сохраняться навсегда, даже при подаче питания, если данные не будут периодически перезаписаны в память. Данные хранятся в качестве заряда на конденсаторах. Заряд на конденсаторе должен периодически обновляться, чтобы предотвратить его утечку. DRAM и устройство с зарядовой связью (CCD) являются примером динамической памяти.