Heap vs. Stak til Delphi-udviklere

Kald funktionen "DoStackOverflow" en gang fra din kode så får du EStackOverflow fejl rejst af Delphi med meddelelsen "stack overflow".


fungere DoStackOverflow: heltal;

begynde

 resultat: = 1 + DoStackOverflow;

ende;

Hvad er denne "stak", og hvorfor er der et overløb der ved hjælp af koden ovenfor?

Så kalder DoStackOverflow-funktionen sig rekursivt - uden en "exit-strategi" - den fortsætter bare med at dreje og afslutter aldrig.

En hurtig løsning, du ville gøre, er at rydde den åbenlyse fejl, du har, og sikre, at funktionen findes på et tidspunkt (så din kode kan fortsætte med at udføre, hvor du har kaldt funktionen).

Du går videre, og du kigger aldrig tilbage og holder ikke af bug / undtagelse, da den nu er løst.

Alligevel forbliver spørgsmålet: hvad er denne stak, og hvorfor er der et overløb?

Hukommelse i dine Delphi-applikationer

Når du begynder at programmere i Delphi, kan du opleve bug som den ovenfor, du ville løse det og gå videre. Denne er relateret til hukommelsesallokering. Det meste af tiden vil du ikke bryde dig om hukommelsesallokering, så længe du fri hvad du opretter.

instagram viewer

Efterhånden som du får mere erfaring i Delphi, begynder du at oprette dine egne klasser, indlede dem, pleje hukommelsestyring og både.

Du kommer til det punkt, hvor du i Hjælp læser noget i retning af "Lokale variabler (deklareret inden for procedurer og funktioner) findes i en applikations stak." og også Klasser er referencetyper, så de ikke kopieres ved tildelingen, de sendes ved henvisning, og de tildeles på bunke.

Så hvad er "stack" og hvad er "heap"?

Stak vs. heap

Kør din applikation på Windows, der er tre områder i hukommelsen, hvor din applikation gemmer data: global hukommelse, heap og stack.

Globale variabler (deres værdier / data) gemmes i den globale hukommelse. Hukommelsen til globale variabler reserveres af din applikation, når programmet starter og forbliver allokeret, indtil dit program afslutter. Hukommelsen for globale variabler kaldes "datasegment".

Da global hukommelse kun én gang er allokeret og frigivet ved programmets afslutning, er vi ligeglad med det i denne artikel.

Stabel og bunke er hvor dynamisk hukommelsesallokering finder sted: når du opretter en variabel til en funktion, når du opretter en forekomst af en klasse, når du sender parametre til en funktion og bruger / videregiver dens resultat værdi.

Hvad er stak?

Når du erklærer en variabel i en funktion, tildeles den hukommelse, der kræves for at holde variablen, fra stakken. Du skriver blot "var x: heltal", bruger "x" i din funktion, og når funktionen afsluttes, er du ligeglad med hukommelsestildeling eller frigørelse. Når variablen går uden for rækkevidden (kode forlader funktionen), frigøres hukommelsen, der blev taget på stakken.

Stakkehukommelsen tildeles dynamisk ved hjælp af LIFO ("sidst i første ud") tilgang.

I Delphi-programmer, bruges stackhukommelse af

  • Lokale rutine (metode, procedure, funktion) variabler.
  • Rutineparametre og returtyper.
  • Windows API-funktion opkald.
  • Optegnelser (dette er grunden til, at du ikke behøver eksplicit at oprette en forekomst af en posttype).

Du behøver ikke eksplicit at frigøre hukommelsen på stakken, da hukommelsen automatisk tildeles til dig, når du f.eks. Erklærer en lokal variabel til en funktion. Når funktionen afsluttes (nogle gange endda før på grund af Delphi-compileroptimering) frigøres hukommelsen til variabelen automatisk magisk.

Stak hukommelsesstørrelse er som standard stor nok til dine (så komplekse som de er) Delphi-programmer. Værdierne "Maksimal stabelstørrelse" og "Minimum stabelstørrelse" på Linker-indstillingerne for dit projekt specificerer standardværdier - i 99,99% behøver du ikke at ændre dette.

Tænk på en stak som en bunke med hukommelsesblokke. Når du erklærer / bruger en lokal variabel, vil Delphi-hukommelsesadministrator vælge blokken fra toppen, bruge den, og når den ikke længere er nødvendig, returneres den tilbage til stakken.

Når der er brugt lokal variabel hukommelse fra stakken, initialiseres lokale variabler ikke, når de deklareres. Angiv en variabel "var x: heltal" i en eller anden funktion, og prøv bare at læse værdien, når du indtaster funktionen - x vil have en "underlig" værdi uden nul. Så initialiser altid (eller indstil værdi) til dine lokale variabler, før du læser deres værdi.

På grund af LIFO er stack (hukommelsesallokering) operationer hurtige, da der kun kræves nogle få operationer (push, pop) for at styre en stack.

Hvad er Heap?

En bunke er et område af hukommelse, hvor dynamisk allokeret hukommelse gemmes. Når du opretter en forekomst af en klasse, tildeles hukommelsen fra dyngen.

I Delphi-programmer bruges heap-hukommelse af / når

  • Oprettelse af et eksempel på en klasse.
  • Oprettelse og størrelse af dynamiske arrays.
  • Allokeret eksplicit hukommelse ved hjælp af GetMem, FreeMem, New og Dispose ().
  • Brug af ANSI / wide / Unicode strenge, varianter, interface (administreres automatisk af Delphi).

Heap-hukommelse har intet pænt layout, hvor der ville være en rækkefølge, der er tildeling af hukommelsesblokke. Heap ligner en dåse kugler. Hukommelsesallokering fra dyngen er tilfældig, en blok herfra end en blok derfra. Heap-operationer er således lidt langsommere end dem på stakken.

Når du beder om en ny hukommelsesblok (dvs. oprette en forekomst af en klasse), vil Delphi hukommelsesadministrator håndtere dette for dig: du får en ny hukommelsesblok eller en brugt og kasseret en.

Heapen består af al virtuel hukommelse (RAM og diskplads).

Manuelt tildele hukommelse

Nu hvor alt om hukommelse er klart, kan du med sikkerhed (i de fleste tilfælde) ignorere ovenstående og blot fortsætte med at skrive Delphi-programmer, som du gjorde i går.

Selvfølgelig skal du være opmærksom på, hvornår og hvordan man manuelt tildeler / frigør hukommelse.

"EStackOverflow" (fra begyndelsen af ​​artiklen) blev hævet, fordi der med hvert opkald til DoStackOverflow er brugt et nyt segment af hukommelse fra stakken, og stakken har begrænsninger. Så simpelt som det.

instagram story viewer