Hívja egyszer a "DoStackOverflow" funkciót a kódod és megkapod a EStackOverflow Delphi által felvetett hiba a "verem túlcsordulása" üzenettel.
funkció DoStackOverflow: egész szám;
kezdődik
eredmény: = 1 + DoStackOverflow;
végén;
Mi ez a "verem", és miért van ott túlcsordulás a fenti kód használatával?
Tehát a DoStackOverflow funkció rekurzívan hívja magát - "kilépési stratégia nélkül" - csak forog, és soha nem lép ki.
Gyors javítás, ha megtenné, törölje a nyilvánvaló hibát, és ellenőrizze, hogy a funkció egy bizonyos pontban létezik-e (így a kódja folytathatja a futtatást attól a helytől, ahova hívta a függvényt).
Haladsz, és soha nem nézel vissza, nem törődsz a hibával / kivétellel, mivel ez már megoldódott.
Ugyanakkor a kérdés továbbra is fennáll: mi ez a verem és miért van túlcsordulás??
Memória a Delphi alkalmazásokban
Amikor elkezdi a programozást a Delphi-ben, előfordulhat, hogy olyan hibát tapasztal, mint a fentiek, megoldja és továbblép. Ez a memóriaelosztáshoz kapcsolódik. Legtöbbször nem fog törődni a memóriaelosztással, amíg te szabadítsa fel azt, amit létrehoz.
Ahogy a Delphi-ben több tapasztalatot szerez, elkezdi létrehozni saját osztályait, közvetítheti őket, törődik a memóriakezeléssel és egyaránt.
Eljut a pontra, ahol a Súgóban olyasmit olvassa el "A helyi változók (az eljárásokon és a funkciókon belül deklaráltak) az alkalmazásban találhatók Kazal." és még Az osztályok referencia típusok, tehát nem másolják őket a hozzárendeléskor, referenciákkal adják át őket, és kiosztják őket halom.
Szóval, mi az a "verem", és mi a "halom"?
Stack vs. Halom
Az alkalmazás futtatása Windows rendszeren, a memóriában három olyan terület található, ahol az alkalmazás tárolja az adatokat: globális memória, halom és verem.
A globális változókat (értéküket / adataikat) a globális memória tárolja. A globális változók számára fenntartott memóriát az alkalmazás fenntartja a program indulásakor, és addig marad lefoglalva, amíg a program le nem fejeződik. A globális változók memóriáját "adatszegmensnek" nevezzük.
Mivel a globális memória csak egyszer van kiosztva és felszabadítva a program befejezésekor, ebben a cikkben nem törődünk vele.
A veremben és a halomban történik a dinamikus memóriaelosztás: amikor egy függvényt létrehoz egy változót, amikor létrehoz egy osztálypéldányt, amikor paramétereket küld egy függvénynek, és felhasználja / átadja annak eredményét érték.
Mi az a verem?
Ha egy változót deklarál egy funkción belül, akkor a változó megtartásához szükséges memóriát a verem fogja kiosztani. Egyszerűen írja a "var x: integer" kifejezést, használja az "x" értéket a funkciójában, és amikor a funkció kilép, akkor nem törődik a memória allokációjával és a felszabadítással. Amikor a változó hatókörén kívül esik (kód kilép a funkciótól), a verembe vett memória felszabadul.
A veremmemóriát a LIFO ("utoljára az elsőben ki") megközelítéssel dinamikusan osztják el.
Ban ben Delphi programok, a veremmemóriát a
- Helyi rutin (módszer, eljárás, funkció) változók.
- Rutin rutinok és visszatérési típusok.
- Windows API funkció felhívja.
- Rekordok (ezért nem kell kifejezetten létrehoznia egy rekordtípus példányát).
Nem kell kifejezetten felszabadítania a veremben lévő memóriát, mivel a memória automatikusan varázslatosan kiosztódik az Ön számára, amikor például egy függvény helyi változóját deklarálja. Amikor a funkció kilép (néha még a Delphi fordító optimalizálása miatt), a változó memóriája automatikusan varázslatosan felszabadul.
Verem memória mérete alapértelmezés szerint elég nagy a (bármilyen összetett) Delphi programhoz. A projekt Linker opciói "Maximális veremméret" és "Minimális veremméret" értékei megadják az alapértelmezett értékeket - 99,99% -ban nem kell módosítania ezt.
Gondolj egy halomra, mint egy halom memóriablokkra. Amikor kijelenti / használja egy helyi változót, a Delphi memóriakezelő felülről kiválasztja a blokkot, felhasználja azt, és amikor már nincs rá szüksége, akkor visszaadja a verembe.
Ha a veremből helyi változó memóriát használunk, akkor a helyi változók nem kerülnek inicializálásra, amikor deklaráljuk. Nyisson meg egy változót "var x: integer" néhány függvényben, és csak próbálja meg kiolvasni az értéket, amikor beírja a függvényt - x lesz valamilyen "furcsa" nulla értéke. Tehát mindig inicializálja (vagy állítsa be az értéket) a helyi változókhoz, mielőtt elolvassa azok értékét.
A LIFO miatt a verem (memória allokáció) műveletek gyorsak, mivel csak néhány műveletre (push, pop) van szükség a verem kezeléséhez.
Mi a halom?
Egy halom a memória olyan területe, amelyben a dinamikusan elosztott memória tárolódik. Amikor létrehoz egy osztálypéldányt, a memóriát a halomból osztják le.
A Delphi programokban a halom memóriát a / mikor használja
- Osztálypéldány létrehozása.
- Dinamikus tömbök létrehozása és átméretezése.
- A memória kifejezett kiosztása a GetMem, FreeMem, New és Dispose () használatával.
- ANSI / széles / Unicode karakterláncok, variációk, interfészek használatával (a Delphi automatikusan kezeli).
A halommemórianak nincs szép elrendezése, ahol lenne valamilyen sorrend a memóriablokkok kiosztására. A halom úgy néz ki, mint egy doboz golyó. A memóriakiosztás a halomból véletlenszerűen történik, innen egy blokk, mint onnan egy blokk. Így a halom műveletek egy kicsit lassabbak, mint a veremben végrehajtottak.
Amikor új memóriablokkot kér (azaz létrehoz egy osztálypéldányt), a Delphi memóriakezelő ezt fogja kezdeni az Ön számára: kapsz egy új memóriablokkot vagy egy használt és eldobott memóriablokkot.
A halom az összes virtuális memóriából (RAM és lemezterület).
A memória kézi elosztása
Most, hogy minden a memóriáról tisztán van, biztonságosan (a legtöbb esetben) figyelmen kívül hagyhatja a fentieket, és egyszerűen folytathatja a Delphi programok írását, ahogy tegnap tette.
Természetesen tisztában kell lennie azzal, hogy mikor és hogyan kell manuálisan elosztani a memóriát.
Az "EStackOverflow" (a cikk elejétől) felmerült, mivel minden DoStackOverflow híváskor a memória új szegmense került felhasználásra a veremből, és a verem korlátozott. Ilyen egyszerű az egész.