Różnica między statyczną alokacją pamięci a dynamiczną alokacją pamięci


Odpowiedzi:


97

Istnieją trzy typy alokacji - statyczne, automatyczne i dynamiczne.

Przydział statyczny oznacza, że ​​pamięć dla zmiennych jest przydzielana podczas uruchamiania programu. Rozmiar jest ustalany podczas tworzenia programu. Dotyczy to zmiennych globalnych, zmiennych o zasięgu pliku i zmiennych kwalifikowanych za pomocą staticzdefiniowanych wewnątrz funkcji.

Automatyczna alokacja pamięci ma miejsce dla (niestatycznych) zmiennych zdefiniowanych w funkcjach i zwykle jest przechowywana na stosie (chociaż standard C nie nakazuje używania stosu). Nie musisz rezerwować dodatkowej pamięci za ich pomocą, ale z drugiej strony masz również ograniczoną kontrolę nad żywotnością tej pamięci. Np .: zmienne automatyczne w funkcji są dostępne tylko do zakończenia funkcji.

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

Dynamiczna alokacja pamięci jest nieco inna. Teraz możesz kontrolować dokładny rozmiar i żywotność tych lokalizacji w pamięci. Jeśli go nie zwolnisz, napotkasz wycieki pamięci, które mogą spowodować awarię aplikacji, ponieważ w pewnym momencie system nie może przydzielić większej ilości pamięci.

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

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

W górnym przykładzie przydzielona pamięć jest nadal ważna i dostępna, mimo że funkcja została zakończona. Kiedy skończysz z pamięcią, musisz ją zwolnić:

free(mem);

2
Na pewno masz kontrolę nad okresem życia zmiennych ... to ty decydujesz o zakresie, prawda?
Luchian Grigore,

Oczywiście, ale nie o to mi chodziło. Nie można przedłużyć okresu istnienia zmiennych, aby przeżyć jego zakres. Ale może powinienem to wyjaśnić w mojej odpowiedzi. Dzięki
Constantinius,

5
-1 Ta odpowiedź jest błędna. Mylisz zmienne statyczne i automatyczne .
brice

2
Twoje zdanie brzmi: „ Przydział statyczny oznacza, że ​​pamięć dla twoich zmiennych jest przydzielana automatycznie ”. To źle . Spójrz, co ma do powiedzenia na ten temat strona podręcznika do biblioteki GNU libc .
brice

1
@EliBendersky Jest teraz przeformułowane. Sprawdź teraz, czy jest poprawne.
Suraj Jain

119

To jest standardowe pytanie do wywiadu:

Dynamiczna alokacja pamięci

Czy pamięć przydzielona w czasie wykonywania przy użyciu calloc(), malloc()i przyjaciół. Czasami jest również nazywana pamięcią „sterty”, chociaż nie ma to nic wspólnego z referencją struktury danych sterty .

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

Pamięć sterty jest trwała do momentu free()wywołania. Innymi słowy, kontrolujesz okres istnienia zmiennej.

Automatyczna alokacja pamięci

Jest to tak zwana pamięć „stosu” i jest ona przydzielana, gdy wprowadzasz nowy zakres (zwykle, gdy nowa funkcja jest umieszczana na stosie wywołań). Po wyjściu z zakresu wartości automatycznych adresów pamięci są nieokreślone i dostęp do nich jest błędem .

int a = 43;

Zauważ, że zasięg niekoniecznie oznacza funkcję. Zakresy mogą zagnieżdżać się w funkcji, a zmienna będzie w zakresie tylko w bloku, w którym została zadeklarowana. Należy również zauważyć, że nie określono miejsca, w którym ta pamięć jest przydzielona. (W rozsądnym systemie będzie na stosie lub w rejestrach do optymalizacji)

Przydział pamięci statycznej

Jest przydzielany w czasie kompilacji * , a okres istnienia zmiennej w pamięci statycznej jest okresem istnienia programu .

W języku C pamięć statyczną można przydzielić za pomocą staticsłowa kluczowego. Zakres jest tylko jednostką kompilacji.

Sprawy stają się bardziej interesujące, gdy externweźmie się pod uwagę słowo kluczowe . Gdy externzmienna jest zdefiniowana, kompilator przydziela jej pamięć. Kiedy deklarowanaextern jest zmienna , kompilator wymaga, aby zmienna była zdefiniowana w innym miejscu. Brak zadeklarowania / zdefiniowania zmiennych spowoduje problemy z łączeniem, a brak zadeklarowania / zdefiniowania zmiennych spowoduje problemy z kompilacją.externstatic

w zakresie pliku słowo kluczowe static jest opcjonalne (poza funkcją):

int a = 32;

Ale nie w zakresie funkcji (wewnątrz funkcji):

static int a = 32;

Technicznie externi staticsą dwiema oddzielnymi klasami zmiennych w C.

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

* Uwagi dotyczące przydzielania pamięci statycznej

Trochę mylące jest stwierdzenie, że pamięć statyczna jest przydzielana w czasie kompilacji, zwłaszcza jeśli zaczniemy rozważać, że maszyna kompilująca i maszyna hosta mogą nie być takie same lub mogą nawet nie być na tej samej architekturze.

Lepszym rozwiązaniem może być myślenie, że alokacja pamięci statycznej jest obsługiwana przez kompilator, a nie przydzielana w czasie kompilacji .

Na przykład kompilator może utworzyć dużą datasekcję w skompilowanym pliku binarnym, a gdy program jest załadowany do pamięci, adres wdatasegment programu zostanie użyty jako lokalizacja przydzielonej pamięci. Ma to wyraźną wadę polegającą na tym, że skompilowany plik binarny jest bardzo duży, jeśli używa dużo pamięci statycznej. Możliwe jest napisanie wielogigabajtowego pliku binarnego wygenerowanego z mniej niż pół tuzina linii kodu. Inną opcją jest dla kompilatora wstrzyknięcie kodu inicjującego, który przydzieli pamięć w inny sposób, zanim program zostanie wykonany. Ten kod będzie się różnić w zależności od platformy docelowej i systemu operacyjnego. W praktyce współczesne kompilatory używają heurystyki, aby zdecydować, której z tych opcji użyć. Możesz to wypróbować samodzielnie, pisząc mały program w języku C, który przydziela dużą tablicę statyczną zawierającą elementy 10k, 1m, 10m, 100m, 1G lub 10G. W przypadku wielu kompilatorów rozmiar binarny będzie wzrastał liniowo wraz z rozmiarem tablicy i przekroczy określony punkt,

Zarejestruj pamięć

Ostatnią klasą pamięci są zmienne „rejestrowe”. Zgodnie z oczekiwaniami, zmienne rejestrowe powinny być alokowane w rejestrze procesora, ale decyzja należy do kompilatora. Nie możesz zamienić zmiennej rejestrowej w odniesienie za pomocą adresu.

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

Większość nowoczesnych kompilatorów jest mądrzejsza od Ciebie w wybieraniu zmiennych, które powinny być umieszczone w rejestrach :)

Bibliografia:


3
Uwaga: int * a = malloc(sizeof(*a));zamiast tego sugerowałbym unikanie powtarzania typu a. To znacznie ułatwia sprawę, jeśli kiedykolwiek rodzaj azmian.
Shahbaz,

1
W rzeczywistości nazywa się to stertą, ale nie ma to nic wspólnego ze strukturą danych sterty. Sterta w tym przypadku oznacza bałagan
dynamiczny

2
„Przydzielanie pamięci statycznej ... jest przydzielane w czasie kompilacji” Czy masz na myśli, że rozmiar alokacji jest określany w czasie kompilacji? Czy odłożenie pamięci nie nastąpiłoby tylko w czasie wykonywania?
lf215

Hej, mam wątpliwości, jeśli nadal odpowiadasz :(. A co z automatycznym przydzielaniem pamięci? Czy kompilator będzie również przechowywać adresy w sekcji danych dla tych zmiennych lokalnych i przekazywać je do pliku wykonywalnego. A kiedy kod jest wykonywany (i wchodzi w zakres ) te adresy będą faktycznie używane jako lokalizacje przydzielonej pamięci. Czy też są przydzielane tylko w czasie wykonywania, bez generowania i obsługi adresu przez mój kompilator?
LocalHost

1
@LocalHost Automatyczne zmienne są ograniczone do okresu istnienia kontekstu (nawiasy klamrowe), w którym zostały zdefiniowane. jest to zwykle przydzielane na stosie wywołań w czasie wykonywania. Na pewno nie jest przechowywany w sekcji danych. Możesz przeczytać standard C18 tutaj: (6.2.4.5-7) web.archive.org/web/20181230041359/http://www.open-std.org/jtc1/…
brice

3

Przydział pamięci statycznej:

  • Zmienne są przydzielane na stałe
  • Alokacja odbywa się przed wykonaniem programu
  • Wykorzystuje strukturę danych zwaną stosem do implementacji alokacji statycznej
  • Mniej wydajne
  • Nie ma możliwości ponownego wykorzystania pamięci

Dynamiczna alokacja pamięci:

  • Zmienne są przydzielane tylko wtedy, gdy jednostka programu jest aktywna
  • Alokacja odbywa się podczas wykonywania programu
  • Wykorzystuje strukturę danych zwaną stertą do implementacji alokacji dynamicznej
  • Bardziej wydajny
  • Istnieje możliwość ponownego wykorzystania pamięci . Pamięć może zostać zwolniona, gdy nie jest wymagana

1
„Statyczny przydział pamięci [...] Wykorzystuje strukturę danych zwaną stosem do implementacji statycznej alokacji” Nie , to jest niepoprawne i mylące. zobacz mój post, aby zobaczyć różnicę między alokacją automatyczną i statyczną. Pamięć statyczna może używać stosu. Jest to silnie zależne od implementacji, a do tego samego wdrożenia można zastosować wiele strategii. Nie jestem też pewien, co rozumiesz przez „mniej wydajne”. @Trieu Toan, zmieniłeś znaczenie tej odpowiedzi złą edycją.
brice

2

Statyczna alokacja pamięci: kompilator przydziela wymaganą przestrzeń pamięci dla zadeklarowanej zmiennej, korzystając z adresu operatora, uzyskuje się zarezerwowany adres, który może być przypisany do zmiennej wskaźnikowej, ponieważ większość zadeklarowanych zmiennych ma pamięć statyczną, sposób przypisywania wartości wskaźnika do zmiennej wskaźnikowej jest znany jako statyczna alokacja pamięci. pamięć jest przypisywana podczas kompilacji.

Dynamiczna alokacja pamięci: wykorzystuje funkcje takie jak malloc () lub calloc () do dynamicznego uzyskiwania pamięci.Jeśli te funkcje są używane do dynamicznego uzyskiwania pamięci, a wartości zwracane przez te funkcje są przypisywane do zmiennych wskaźnikowych, takie przypisania są znane jako pamięć dynamiczna Alokacja. pamięć jest przydzielana w czasie wykonywania.


1

Różnica między statyczna pamięć PRZYDZIELANIA & pamięć dynamiczna PRZYDZIELANIA

Pamięć jest przydzielana przed rozpoczęciem wykonywania programu (podczas kompilacji).
Pamięć jest przydzielana podczas wykonywania programu.

Podczas wykonywania nie są wykonywane żadne akcje alokacji ani zwalniania pamięci.
Powiązania pamięci są ustanawiane i niszczone podczas wykonywania.

Zmienne pozostają na stałe przydzielone.
Przydzielane tylko wtedy, gdy jednostka programu jest aktywna.

Realizowane za pomocą stosów i stert.
Wdrożone przy użyciu segmentów danych.

Aby uzyskać dostęp do zmiennych, potrzebny jest wskaźnik.
Nie ma potrzeby dynamicznie przydzielanych wskaźników.

Szybsze wykonanie niż dynamiczne.
Wolniejsze wykonanie niż statyczne.

Wymagane więcej miejsca w pamięci.
Wymagana mniejsza ilość miejsca w pamięci.


1
statyczna alokacja pamięci jest przydzielana na stosie, podczas gdy dynamiczna alokacja pamięci jest przydzielana na stercie
Usman Kurd

@UsmanKurd To generalnie niepoprawne w odniesieniu do pamięci statycznej. Zobacz moją odpowiedź.
brice

0

Przydział pamięci statycznej jest przydzielany w pamięci przed wykonaniem programu pf w czasie kompilacji. Dynamiczna alokacja pamięci to pamięć alokowana podczas wykonywania programu w czasie wykonywania.


-1

Przydział pamięci statycznej. Przydzielona pamięć będzie na stosie.

int a[10];

Dynamiczna alokacja pamięci. Przydzielona pamięć będzie w stercie.

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

a ten ostatni powinien być wolny d, ponieważ w C. nie ma Garbage Collectora (GC).

free(a);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.