267463a542e39a66f60c760defc18530
Programmeringsbøger forklarer, at værdityper oprettes på **stack**, og referencetyper oprettes på **heap**, uden at forklare, hvad disse to ting er. Jeg har ikke læst en klar forklaring på dette. Jeg forstår, hvad *en stack* er. Men,


* Hvor og hvad er de (fysisk i en rigtig computers hukommelse)?
* I hvilket omfang styres de af operativsystemet eller sprogets run-time?
* Hvad er deres anvendelsesområde?
* Hvad bestemmer størrelsen af hver af dem?
* Hvad gør en af dem hurtigere?

Hvad og hvor er stakken og bunken?
==================================


answer-id.com
2021.43
**Stack:**


* Opbevares i computerens RAM ligesom heap (bunken).
* Variabler, der er oprettet på stakken, vil gå ud af rækkevidde og bliver automatisk deallokeret.
* Meget hurtigere at allokere i forhold til variabler på heap.
* Implementeret med en egentlig stack-datastruktur.
* Lagrer lokale data, returadresser, bruges til parameteroverdragelse.
* Der kan opstå et stackoverløb, når der bruges for meget af stakken (oftest ved uendelig eller for dyb rekursion, meget store allokeringer).
* Data oprettet på stakken kan bruges uden pointere.
* Du vil bruge stakken, hvis du ved præcis, hvor mange data du skal allokere før kompileringstidspunktet, og det ikke er for stort.
* Har normalt en maksimal størrelse, der allerede er fastlagt, når dit program starter.


**Heap:**


* Opbevares i computerens RAM ligesom stakken.
* I C++ skal variabler på heap'en destrueres manuelt og falder aldrig uden for rækkevidde. Dataene frigives med `delete`, `delete[]` eller `free`.
* Langsommere at allokere i forhold til variabler på stakken.
* Bruges ved behov til at allokere en blok data til brug for programmet.
* Kan have fragmentering, når der er mange allokeringer og deallokeringer.
* I C++ eller C vil data, der oprettes på heap, blive peget på af pointere og allokeret med henholdsvis `new` eller `malloc`.
* Der kan forekomme fejl i allokeringen, hvis der anmodes om at allokere en for stor buffer.
* Du vil bruge heap'en, hvis du ikke ved præcis, hvor mange data du har brug for på køretidspunktet, eller hvis du skal allokere mange data.
* Ansvarlig for hukommelseslækager.


**Eksempel:**



```
int foo()
{
  char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack).
  bool b = true; // Allocated on the stack.
  if(b)
  {
    //Create 500 bytes on the stack
    char buffer[500];

    //Create 500 bytes on the heap
    pBuffer = new char[500];

   }//<-- buffer is deallocated here, pBuffer is not
}//<--- oops there's a memory leak, I should have called delete[] pBuffer;
```

**The Stack**
Når du kalder en funktion, lægges argumenterne til den pågældende funktion plus andet overhead på stakken. Nogle oplysninger (f.eks. hvor den skal gå hen ved returnering) gemmes også der.
Når du deklarerer en variabel inde i din funktion, allokeres denne variabel også på stakken.


Det er ret enkelt at deallokere stakken, fordi du altid deallokerer i den omvendte rækkefølge, som du allokerer. Stack-ting tilføjes, når du går ind i funktioner, og de tilsvarende data fjernes, når du forlader dem. Det betyder, at man har en tendens til at holde sig inden for et lille område af stakken, medmindre man kalder mange funktioner, der kalder mange andre funktioner (eller skaber en rekursiv løsning).


**The Heap**
Heap er en generisk betegnelse for, hvor du lægger de data, som du opretter i farten. Hvis du ikke ved, hvor mange rumskibe dit program skal oprette, vil du sandsynligvis bruge new-operatoren (eller malloc-operatoren eller tilsvarende) til at oprette hvert rumskib. Denne allokering vil blive hængende i et stykke tid, så det er sandsynligt, at vi vil frigøre tingene i en anden rækkefølge, end vi oprettede dem.


Heap'en er således langt mere kompleks, fordi der ender med at være regioner af hukommelse, der ikke er ubrugte, mellemlagt med chunks, der er det - hukommelsen bliver fragmenteret. Det er et vanskeligt problem at finde ledig hukommelse af den størrelse, man har brug for. Derfor bør man undgå heap'en (selv om den stadig ofte bruges).


**Implementering**
Implementeringen af både stack og heap er normalt op til runtime/OS. Ofte skaber spil og andre applikationer, der er ydelseskritiske, deres egne hukommelsesløsninger, der henter en stor del af hukommelsen fra heap'en og derefter uddeler den internt for at undgå at være afhængige af OS'et for hukommelse.


Dette er kun praktisk, hvis din hukommelsesanvendelse er helt anderledes end normen - dvs. for spil, hvor du indlæser en bane i én stor operation og kan smide hele molevitten væk i en anden stor operation.


**Fysisk placering i hukommelsen**
Dette er mindre relevant, end du tror, på grund af en teknologi kaldet [Virtual Memory](https://en.wikipedia.org/wiki/Virtual_memory), som får dit program til at tro, at du har adgang til en bestemt adresse, hvor de fysiske data befinder sig et andet sted (selv på harddisken!). De adresser, du får til stakken, er i stigende rækkefølge, efterhånden som dit call tree bliver dybere. Adresserne til heap'en er uforudsigelige (dvs. implementeringsspecifikke) og er ærlig talt ikke vigtige.


Stakken er en del af hukommelsen, der kan manipuleres via flere vigtige assemblerinstruktioner, f.eks. 'pop' (fjerne og returnere en værdi fra stakken) og 'push' (skubbe en værdi til stakken), men også call (kalde en underrutine - dette skubber adressen for at vende tilbage til stakken) og return (vende tilbage fra en underrutine - dette fjerner adressen fra stakken og hopper til den). Det er hukommelsesområdet under stackpointerregistret, som kan indstilles efter behov. Stakken bruges også til at videregive argumenter til underprogrammer og også til at bevare værdierne i registrene, før underprogrammer kaldes.


Heap er en del af hukommelsen, der gives til et program af operativsystemet, typisk gennem et syscall som malloc. På moderne operativsystemer er denne hukommelse et sæt sider, som kun den kaldende proces har adgang til.


Størrelsen af stakken bestemmes ved kørslen og vokser normalt ikke efter programmets start. I et C-program skal stakken være stor nok til at rumme alle variabler, der er deklareret i hver funktion. Heap'en vokser dynamisk efter behov, men det er i sidste ende OS, der foretager opkaldet (det vil ofte vokse heap'en med mere end den værdi, der anmodes om af malloc, så i det mindste nogle fremtidige malloc'er ikke behøver at gå tilbage til kernen for at få mere hukommelse. Denne adfærd kan ofte tilpasses)


Fordi du har allokeret stakken før du starter programmet, behøver du aldrig at malloc'e før du kan bruge stakken, så det er en lille fordel der. I praksis er det meget svært at forudsige, hvad der vil være hurtigt og hvad der vil være langsomt i moderne styresystemer, der har virtuelle hukommelsesundersystemer, fordi det er en implementeringsdetalje, hvordan siderne implementeres, og hvor de gemmes. 

