Programmeertaalboeken leggen uit dat waardetypen op de stapel worden aangemaakt, en referentietypen op de heap, zonder uit te leggen wat deze twee dingen zijn. Ik heb hier nog geen duidelijke uitleg van gelezen. Ik begrijp wat een stack is. Maar,
Stack:
Heap:
delete
, delete[]
, of free
.new
of malloc
.Voorbeeld:
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;
De stack Wanneer je een functie aanroept, worden de argumenten voor die functie plus wat andere overhead op de stack gezet. Sommige informatie (zoals waarheen te gaan bij terugkeer) wordt daar ook opgeslagen. Wanneer je een variabele declareert binnen je functie, wordt die variabele ook gealloceerd op de stack.
Het dealloceren van de stack is vrij eenvoudig omdat je altijd dealloceert in de omgekeerde volgorde waarin je alloceert. Stack stuff wordt toegevoegd als je functies binnengaat, de corresponderende data wordt verwijderd als je ze verlaat. Dit betekent dat je de neiging hebt om binnen een klein gebied van de stack te blijven, tenzij je veel functies aanroept die weer veel andere functies aanroepen (of een recursieve oplossing maakt).
De Heap De heap is een algemene naam voor de plaats waar je de gegevens plaatst die je on the fly aanmaakt. Als u niet weet hoeveel ruimteschepen uw programma gaat maken, zult u waarschijnlijk de operator new (of malloc of equivalent) gebruiken om elk ruimteschip te maken. Deze toewijzing blijft een tijdje hangen, dus het is waarschijnlijk dat we dingen in een andere volgorde zullen vrijmaken dan we ze hebben aangemaakt.
De heap is dus veel complexer, omdat er uiteindelijk ongebruikte geheugengebieden zijn, afgewisseld met brokken die dat wel zijn - geheugen raakt gefragmenteerd. Het vinden van vrij geheugen van de grootte die je nodig hebt is een moeilijk probleem. Dit is de reden waarom de heap vermeden moet worden (hoewel hij nog vaak gebruikt wordt).
Implementatie De implementatie van zowel de stack als de heap wordt meestal overgelaten aan de runtime / het OS. Vaak maken games en andere toepassingen die prestatie-kritisch zijn hun eigen geheugen-oplossingen die een groot stuk geheugen van de heap pakken en het dan intern uitdelen om te vermijden dat ze voor geheugen afhankelijk zijn van het OS.
Dit is alleen praktisch als je geheugengebruik nogal afwijkt van de norm - bv. voor spellen waar je een level in één grote operatie laadt en de hele boel in een andere grote operatie kan weggooien.
Fysieke locatie in het geheugen Dit is minder relevant dan je denkt vanwege een technologie genaamd Virtueel Geheugen die je programma laat denken dat je toegang hebt tot een bepaald adres waar de fysieke data ergens anders is (zelfs op de harde schijf!). De adressen die je krijgt voor de stack zijn in oplopende volgorde naarmate je aanroepboom dieper wordt. De adressen voor de heap zijn niet voorspelbaar (d.w.z. implimentatie-specifiek) en eerlijk gezegd niet belangrijk.
De stack is een gedeelte van het geheugen dat kan worden gemanipuleerd via verschillende belangrijke assembleertaalinstructies, zoals 'pop' (een waarde van de stack verwijderen en teruggeven) en 'push' (een waarde naar de stack pushen), maar ook call (een subroutine oproepen - dit duwt het adres om terug te keren naar de stack) en return (terugkeren van een subroutine - dit haalt het adres van de stack af en springt ernaar toe). Het is het gebied van geheugen onder het stack pointer register, dat naar behoefte kan worden ingesteld. De stack wordt ook gebruikt voor het doorgeven van argumenten aan subroutines, en ook voor het bewaren van de waarden in registers voordat subroutines worden aangeroepen.
De heap is een deel van het geheugen dat door het besturingssysteem aan een applicatie wordt gegeven, meestal via een syscall zoals malloc. In moderne besturingssystemen is dit geheugen een set van pagina's waar alleen het aanroepende proces toegang toe heeft.
De grootte van de stack wordt bepaald tijdens runtime, en groeit over het algemeen niet nadat het programma is gestart. In een C-programma moet de stack groot genoeg zijn om elke variabele te bevatten die binnen elke functie wordt gedeclareerd. De heap zal dynamisch groeien als dat nodig is, maar het OS doet uiteindelijk de oproep (het zal vaak de heap laten groeien met meer dan de waarde die door malloc wordt gevraagd, zodat tenminste sommige toekomstige mallocs niet terug naar de kernel hoeven te gaan om meer geheugen te krijgen. Dit gedrag is vaak aanpasbaar)
Omdat je'de stack hebt toegewezen voordat je het programma start, hoef je nooit te mallocen voordat je de stack kunt gebruiken, dus dat'is daar een klein voordeel. In de praktijk is het's heel moeilijk te voorspellen wat snel en wat traag zal zijn in moderne besturingssystemen die virtuele geheugensubsystemen hebben, omdat hoe de pagina's zijn geïmplementeerd en waar ze worden opgeslagen een implementatiedetail is.