Різниця між статичним розподілом пам’яті та динамічним розподілом пам’яті


Відповіді:


91

Існує три типи розподілу - статичний, автоматичний та динамічний.

Статичний розподіл означає, що пам'ять для ваших змінних виділяється під час запуску програми. Розмір фіксується під час створення програми. Це застосовується до глобальних змінних, змінних області файлу та змінних, кваліфікованих за допомогою 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
Звичайно, ви контролюєте термін служби змінних ... Ви вирішуєте сферу застосування, чи не так?
Luchian Grigore

Звичайно, але це не те, що я мав на увазі. Ви не можете продовжити термін служби змінних, щоб пережити його обсяг. Але, можливо, мені слід пояснити це у своїй відповіді. Дякую
Костянтину

5
-1 Ця відповідь неправильна. Ви плутаєте статичні та автоматичні змінні.
brice

2
Ваше власне речення говорить: " Статичний розподіл означає, що пам'ять для ваших змінних автоматично виділяється" Це неправильно . Подивіться, що про це говорить сторінка керівництва для libc GNU .
brice

1
@EliBendersky Зараз це перефразується. Перевірте, чи правильно це зараз.
Suraj Jain

116

Це стандартне запитання для співбесіди:

Динамічне виділення пам'яті

Є чи пам'яті , виділені під час виконання , використовуючи calloc(), malloc()і друзі. Іноді її також називають "кучевою" пам'яттю, хоча вона не має нічого спільного із структурою даних кучі ref .

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сегмент програми буде використовуватися як місце розташування виділеної пам'яті. Це має помітний недолік - зробити скомпільований двійковий файл дуже великим, якщо використовується велика кількість статичної пам'яті. Можна написати багатогігабайтний двійковий файл, згенерований менш ніж з півдюжини рядків коду. Інший варіант - компілятор ввести код ініціалізації, який виділить пам’ять якимось іншим способом перед запуском програми. Цей код буде залежати від цільової платформи та ОС. На практиці сучасні компілятори використовують евристику, щоб вирішити, який із цих варіантів використовувати. Ви можете спробувати це самостійно, написавши невелику програму на С, яка виділяє великий статичний масив із елементів 10k, 1m, 10m, 100m, 1G або 10G. Для багатьох компіляторів бінарний розмір буде продовжувати зростати лінійно із розміром масиву, і минувши певну точку,

Зареєструвати пам'ять

Останнім класом пам’яті є змінні 'register'. Як і слід було очікувати, змінні реєстру повинні бути розподілені в реєстрі ЦП, але рішення фактично залишається за компілятором. Ви не можете перетворити змінну реєстру на посилання, використовуючи адресу-of.

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змін.
Шахбаз,

1
Насправді це називається купа, але це не має нічого спільного зі структурою даних купи. Купи в цьому випадку означає безладне місце
динамічний

2
"Виділення статичної пам'яті ... Виділяється під час компіляції" Ви маєте на увазі, що розмір виділення визначається під час компіляції? Хіба відкладання пам'яті не відбудеться лише під час виконання?
lf215,

2

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

Динамічне розподіл пам'яті: Він використовує такі функції, як malloc () або calloc (), щоб динамічно отримувати пам'ять. Якщо ці функції використовуються для динамічного отримання пам'яті, а значення, що повертаються цими функціями, відносяться до змінних покажчика, такі призначення відомі як динамічна пам'ять allocation.memory призначається під час виконання.


2

Виділення статичної пам'яті:

  • Змінні виділяються постійно
  • Розподіл здійснюється перед виконанням програми
  • Він використовує структуру даних, яка називається стеком, для реалізації статичного розподілу
  • Менш ефективний
  • Там немає ні пам'яті багаторазового використання

Динамічне розподіл пам'яті:

  • Змінні розподіляються, лише якщо програмний блок активується
  • Розподіл здійснюється під час виконання програми
  • Він використовує структуру даних, яку називають купою, для реалізації динамічного розподілу
  • Більш ефективний
  • Існує багаторазове використання пам'яті . Пам'ять можна звільнити, коли це не потрібно

1
"Розподіл статичної пам'яті [...] Він використовує структуру даних, яка називається стеком, для реалізації статичного розподілу" Ні , це неправильно і вводить в оману. Будь ласка, перегляньте мій пост про різницю між автоматичним та статичним розподілом. Статична пам’ять може використовувати стек. Це сильно залежить від реалізації, і для однієї і тієї ж реалізації можна використовувати кілька стратегій. Я також не впевнений, що ви маєте на увазі під "менш ефективним". @Trieu Toan, ти змінив значення цієї відповіді поганою редакцією.
brice

1

Різниця між СТАТИЧНИМ РОЗПОДІЛОМ ПАМ’ЯТІ І ДИНАМІЧНИМ РОЗПОДІЛОМ ПАМ’ЯТІ

Пам'ять виділяється до початку виконання програми (Під час компіляції).
Пам'ять виділяється під час виконання програми.

Під час виконання не виконуються дії з виділення або звільнення пам'яті.
Прив’язки пам’яті встановлюються та руйнуються під час Страти.

Змінні залишаються постійно розподіленими.
Виділяється лише тоді, коли активний програмний блок.

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

Для доступу до змінних потрібен вказівник.
Немає необхідності в динамічно розподілених покажчиках.

Швидше виконання, ніж динамічне.
Повільніше виконання, ніж статичне.

Потрібно більше місця в пам'яті.
Потрібно менше місця в пам'яті.


1
статичне виділення пам'яті розподіляється у стеці, а динамічне виділення пам'яті - у купі
курд Усмана

@UsmanKurd Це, як правило, неправильно щодо статичної пам'яті. Дивіться мою відповідь.
brice

0

Виділення статичної пам'яті виділяється пам’яттю перед виконанням програми pf під час компіляції. Динамічне виділення пам'яті - це виділена пам’ять під час виконання програми під час виконання.


-1

Розподіл статичної пам'яті. Виділена пам’ять буде в стосі.

int a[10];

Динамічне виділення пам'яті. Виділена пам’ять буде в купі.

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

а останній повинен бути вільним d, оскільки в C. немає збирача сміття (GC).

free(a);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.