Enkrat pokličite funkcijo "DoStackOverflow" svojo kodo in dobili boste EStackOverflow napaka, ki jo je Delphi povzročil s sporočilom "preliv sklada".
funkcijo DoStackOverflow: celo število;
začeti
rezultat: = 1 + DoStackOverflow;
konec;
Kaj je to "sklad" in zakaj je tam preliv z uporabo zgornje kode?
Torej, funkcija DoStackOverflow se rekurzivno kliče - brez "izhodne strategije" - se še naprej vrti in se nikoli ne ustavi.
Hitro popravilo bi bilo, da očistite očitno napako, ki jo imate, in zagotovite, da funkcija ob nekem trenutku obstaja (tako da lahko koda še naprej izvaja, od koder ste poklicali funkcijo).
Greš naprej in se nikoli ne oziraš nazaj, ne skrbi za napako / izjemo, kot je zdaj rešena.
Še vedno pa ostaja vprašanje: kaj je ta kup in zakaj pride do preliva?
Pomnilnik v vaših Delphi aplikacijah
Ko začnete programirati v Delphiju, lahko naletite na hrošča, kot je zgornji, ga rešite in nadaljujete. Ta je povezana z dodelitvijo pomnilnika. Večino časa ne bi skrbeli za dodeljevanje pomnilnika, dokler ne zastonj tisto, kar ustvariš.
Ko pridobivate več izkušenj z Delphi, začnete ustvarjati lastne razrede, jih sprožate, skrbite za upravljanje pomnilnika in podobno.
Došli boste do točke, ko boste v pomoči prebrali nekaj podobnega "Lokalne spremenljivke (deklarirane v postopkih in funkcijah) so v aplikaciji zložiti." in tudi Razredi so referenčni tipi, zato se pri nalogi ne kopirajo, se posredujejo po referencah in so razporejeni na kup.
Torej, kaj je "stack" in kaj je "heap"?
Stack vs. Kup
Zagon aplikacije v sistemu Windows, v pomnilniku so tri področja, kjer vaša aplikacija shranjuje podatke: globalni pomnilnik, kopica in zlaganje.
Globalne spremenljivke (njihove vrednosti / podatki) so shranjene v globalnem pomnilniku. Pomnilnik za globalne spremenljivke si rezervira vaša aplikacija, ko se program zažene in ostane dodeljen, dokler se program ne ustavi. Pomnilnik za globalne spremenljivke se imenuje "podatkovni segment".
Ker je globalni pomnilnik le enkrat dodeljen in sproščen ob zaključku programa, nam tega članka v tem članku ni mar.
Zlaganje in kopica sta tam, kjer poteka dinamična dodelitev pomnilnika: ko ustvarite spremenljivko za funkcijo, ko ustvarite primerek razreda, ko pošljete parametre funkciji in uporabite / prenesete njen rezultat vrednost.
Kaj je stack?
Ko deklarirate spremenljivko znotraj funkcije, se iz sklada dodeli pomnilnik, potreben za shranjevanje spremenljivke. Preprosto napišete "var x: integer", v svoji funkciji uporabite "x", in ko funkcija izstopi, vas ne zanima niti dodelitev spomina niti sprostitev. Ko spremenljivka izstopi iz področja (koda izstopi iz funkcije), se sprosti pomnilnik, ki je bil vzet v sveženju.
Pomnilnik skladbe se dodeli dinamično z LIFO ("last in first out") pristopom.
V Programi Delphi, pomnilnik skladanja uporablja
- Lokalne rutinske (metoda, postopek, funkcija) spremenljivke.
- Rutinski parametri in vrste vrnitve.
- Windows API funkcija klici.
- Zapisi (zato vam ni treba izrecno ustvariti primerka vrste zapisa).
Ni vam treba izrecno osvoboditi pomnilnika na skladanju, saj je pomnilnik za vas samodejno čarobno dodeljen, ko na primer deklarirate lokalno spremenljivko za funkcijo. Ko funkcija izgine (včasih tudi prej zaradi optimizacije prevajalnika Delphi), se pomnilnik spremenljivke samodejno čarobno sprosti.
Velikost pomnilnika skladite je privzeto dovolj velik za vaše (tako zapletene) programe Delphi. Vrednosti "Največja velikost nabora" in "Najmanjša velikost nizov" v možnostih Linker za vaš projekt določata privzete vrednosti - v 99,99% vam tega ne bi bilo treba spreminjati.
Zamislite si kup kot kup spominskih blokov. Ko razglasite / uporabite lokalno spremenljivko, bo upravitelj pomnilnika Delphi izbral blok z vrha, ga uporabil, ko ga ne potrebujete, pa ga bo vrnil nazaj v sklad.
Ob uporabi lokalnega pomnilnika spremenljivk iz sklada se lokalne spremenljivke ob deklaraciji ne inicializirajo. Izjavite spremenljivko "var x: integer" v neki funkciji in poskusite brati vrednost, ko vnesete funkcijo - x bo imelo nekaj "čudne" ničle vrednosti. Torej, vedno preberite (ali nastavite vrednost) na svoje lokalne spremenljivke, preden preberete njihovo vrednost.
Zaradi LIFO so operacije zlaganja (dodelitev pomnilnika) hitre, saj je za upravljanje sklada potrebno le nekaj operacij (push, pop).
Kaj je kup?
Kopča je območje pomnilnika, v katerem je shranjen dinamično dodeljeni pomnilnik. Ko ustvarite primerek razreda, se pomnilnik dodeli iz kopice.
V programih Delphi uporabimo heap spomin /, ko
- Ustvarjanje primerka razreda.
- Ustvarjanje in spreminjanje velikosti dinamičnih nizov.
- Izrecna dodelitev pomnilnika s pomočjo GetMem, FreeMem, New in Dispose ().
- Uporaba nizov ANSI / širok / Unicode, različice, vmesniki (samodejno upravlja Delphi).
Heap pomnilnik nima lepe postavitve, kjer bi bil nekaj vrstnega reda dodeljevanje blokov pomnilnika. Heap je videti kot pločevinka iz marmorja. Dodelitev spomina iz kopice je naključna, blok od tu kot blok od tam. Tako so kopice delovale nekoliko počasneje kot tiste na kupu.
Ko vprašate za nov pomnilniški blok (tj. Ustvarite primerek razreda), bo upravitelj pomnilnika Delphi to rešil namesto vas: dobili boste nov pomnilniški blok ali rabljenega in zavrženi.
Kopica je sestavljena iz vsega virtualnega pomnilnika (RAM in prostor na disku).
Ročno dodeljevanje spomina
Zdaj, ko je vse o pomnilniku jasno, lahko varno (v večini primerov) prezrete zgoraj in preprosto nadaljujete s pisanjem programov Delphi, kot ste ga naredili včeraj.
Seveda se morate zavedati, kdaj in kako ročno dodeliti / osvoboditi pomnilnik.
"EStackOverflow" (od začetka članka) je bil postavljen, ker je z vsakim klicem na DoStackOverflow uporabljen nov segment pomnilnika iz sklada in stack ima omejitve. Tako enostavno kot to.