Heap vs. Stack for Delphi Developers

Kall funksjonen "DoStackOverflow" en gang fra koden din så får du EStackOverflow feil reist av Delphi med meldingen "stack overflow".


funksjon DoStackOverflow: heltall;

begynne

 resultat: = 1 + DoStackOverflow;

slutt;

Hva er denne "stabelen", og hvorfor er det et overløp der ved hjelp av koden over?

Så, DoStackOverflow-funksjonen kaller seg rekursivt - uten en "exit-strategi" - den fortsetter bare å snurre og kommer aldri ut.

En rask løsning, vil du gjøre, er å fjerne den åpenbare feilen du har, og sikre at funksjonen eksisterer på et tidspunkt (slik at koden din kan fortsette å utføre der du har kalt funksjonen).

Du går videre, og ser aldri tilbake, og bryr deg ikke om feilen / unntaket slik det nå er løst.

Likevel gjenstår spørsmålet: hva er denne stabelen og hvorfor er det et overløp?

Minne i Delphi-applikasjonene

Når du begynner å programmere i Delphi, kan du oppleve feil som den ovenfor, du ville løse den og gå videre. Denne er relatert til minnetildeling. Det meste av tiden ville du ikke bryr deg om minnetildeling så lenge du frigjøre det du lager.

instagram viewer

Etter hvert som du får mer erfaring i Delphi, begynner du å lage dine egne klasser, opprette dem, bry deg om minnestyring og like.

Du kommer til det punktet hvor du vil lese, i hjelpen, noe som "Lokale variabler (deklarert i prosedyrer og funksjoner) ligger i en applikasjons stable." og også Klassene er referansetyper, så de blir ikke kopiert på oppgaven, de sendes ved referanse, og de blir tildelt på heap.

Så, hva er "stack" og hva er "heap"?

Stabel vs. heap

Kjører applikasjonen din på Windows, er det tre områder i minnet der applikasjonen din lagrer data: globalt minne, heap og stack.

Globale variabler (verdiene / dataene) lagres i det globale minnet. Minnet for globale variabler er reservert av applikasjonen din når programmet starter og forblir tildelt til programmet avsluttes. Hukommelsen for globale variabler kalles "datasegment".

Siden det globale minnet bare en gang blir tildelt og frigjort ved programavslutning, bryr vi oss ikke om det i denne artikkelen.

Stabel og haug er der dynamisk minnetildeling foregår: når du oppretter en variabel for en funksjon, når du oppretter en forekomst av en klasse når du sender parametere til en funksjon og bruker / passerer resultatet verdi.

Hva er stabel?

Når du deklarerer en variabel i en funksjon, blir minnet som kreves for å holde variabelen tildelt fra bunken. Du skriver ganske enkelt "var x: heltall", bruker "x" i funksjonen din, og når funksjonen går ut bryr du deg ikke om minnetildeling eller frigjøring. Når variabelen går utenfor omfanget (kode går ut av funksjonen), frigjøres minnet som ble tatt på bunken.

Stabelminnet tildeles dynamisk ved bruk av LIFO ("sist inn først ut").

I Delphi-programmer, brukes stackminne av

  • Lokale rutiner (metode, prosedyre, funksjon) variabler.
  • Rutineparametere og returtyper.
  • Windows API-funksjon samtaler.
  • Poster (dette er grunnen til at du ikke eksplisitt trenger å opprette en forekomst av en posttype).

Du trenger ikke eksplisitt å frigjøre minnet på bunken, da minnet automatisk tildeles til deg når du for eksempel erklærer en lokal variabel til en funksjon. Når funksjonen går ut (noen ganger også før på grunn av Delphi-kompilatoroptimalisering), blir minnet for variabelen frigjort automatisk.

Stabel minne størrelse er som standard stor nok for dine (så komplekse som de er) Delphi-programmer. Verdiene "Maksimal stabelstørrelse" og "Minimum stabelstørrelse" på Linker-alternativene for prosjektet ditt angir standardverdier - i 99,99% trenger du ikke å endre dette.

Tenk på en stabel som en haug med minneblokker. Når du erklærer / bruker en lokal variabel, vil Delphi minnebehandler velge blokken fra toppen, bruke den, og når den ikke lenger er nødvendig, vil den bli returnert tilbake til bunken.

Når det er brukt lokalt variabelt minne fra stabelen, initialiseres ikke lokale variabler når deklareres. Forklar en variabel "var x: heltall" i en eller annen funksjon, og prøv bare å lese verdien når du går inn i funksjonen - x vil ha noen "rare" verdi som ikke er null. Så initialiser alltid (eller sett verdien) til de lokale variablene før du leser verdien.

På grunn av LIFO er det hurtig (minneallokering) -operasjoner som ettersom bare noen få operasjoner (push, pop) er nødvendige for å administrere en stabel.

Hva er bunke?

En haug er et minneområde der dynamisk allokert minne lagres. Når du oppretter en forekomst av en klasse, blir minnet tildelt fra haugen.

I Delphi-programmer brukes heap-minne av / når

  • Opprette et eksempel på en klasse.
  • Opprette og endre størrelse på dynamiske matriser.
  • Allokerer eksplisitt minne ved hjelp av GetMem, FreeMem, New og Dispose ().
  • Bruker ANSI / wide / Unicode strenger, varianter, grensesnitt (administreres automatisk av Delphi).

Heap-minne har ingen fine oppsett der det vil være en viss rekkefølge tilordner blokker med minne. Heap ser ut som en boks med klinkekuler. Minnetildeling fra haugen er tilfeldig, en blokk herfra enn en blokk derfra. Dermed er bunkeoperasjoner litt tregere enn de som er på stabelen.

Når du ber om en ny minneblokk (dvs. opprette en forekomst av en klasse), vil Delphi minnebehandler håndtere dette for deg: du får en ny minneblokk eller en brukt og forkastet.

Heapen består av alt virtuelt minne (RAM og diskplass).

Manuelt tildele minne

Nå som alt om minne er klart, kan du trygt (i de fleste tilfeller) ignorere ovenstående og bare fortsette å skrive Delphi-programmer som du gjorde i går.

Selvfølgelig bør du være klar over når og hvordan du tildeler / frigjør manuelt manuelt.

"EStackOverflow" (fra begynnelsen av artikkelen) ble hevet fordi det med hvert anrop til DoStackOverflow er blitt brukt et nytt segment minne fra bunken og bunken har begrensninger. Så enkelt som det.