Vyvolajte funkciu „DoStackOverflow“ raz z váš kód a dostanete EStackOverflow chyba vyvolaná spoločnosťou Delphi so správou „pretečenie zásobníka“.
funkcie DoStackOverflow: celé číslo;
začať
výsledok: = 1 + DoStackOverflow;
koniec;
Čo je to „zásobník“ a prečo v ňom existuje pretečenie pomocou vyššie uvedeného kódu?
Takže funkcia DoStackOverflow sa rekurzívne volá sama - bez „stratégie ukončenia“ - jednoducho sa točí a nikdy sa neopúšťa.
Rýchla oprava, ktorú by ste urobili, je vymazať zjavnú chybu, ktorá sa vyskytla, a ubezpečiť sa, že funkcia v určitom okamihu existuje (aby váš kód mohol pokračovať vo vykonávaní od miesta, kde ste funkciu nazvali).
Pohybujete sa ďalej a nikdy sa nepozeráte späť, nestaráte sa o chybu / výnimku, pretože je teraz vyriešená.
Otázkou však zostáva: čo je tento balík a prečo dochádza k pretečeniu?
Pamäť vo vašich aplikáciách Delphi
Keď začnete programovať v Delphi, môžete zaznamenať chybu, ako je tá vyššie, vyriešili by ste ju a pokračovali ďalej. Táto súvisí s pridelením pamäte. Väčšinu času by vám záležalo na prideľovaní pamäte tak dlho, ako vy
zadarmo, čo vytvoríte.Keď získate viac skúseností s programom Delphi, začnete vytvárať svoje vlastné triedy, spúšťať ich, starať sa o správu pamäte a podobne.
Dostanete sa k bodu, kde si v Pomocníkovi prečítate niečo podobné „Lokálne premenné (deklarované v rámci procedúr a funkcií) sú umiestnené v aplikácii stoh." a tiež Triedy sú referenčné typy, takže sa pri priradení nekopírujú, prechádzajú referenciou a prideľujú sa na internete halda.
Čo je to „stack“ a čo je „halda“?
Stack vs halda
Spustenie aplikácie v systéme Windows, v pamäti aplikácie sú tri oblasti: globálna pamäť, halda a zásobník.
Globálne premenné (ich hodnoty / dáta) sú uložené v globálnej pamäti. Pamäť pre globálne premenné je rezervovaná aplikáciou pri spustení programu a zostáva pridelená, kým sa program neskončí. Pamäť pre globálne premenné sa nazýva „dátový segment“.
Keďže globálna pamäť je pri ukončení programu alokovaná iba raz, v tomto článku sa o ňu nestaráme.
Zásobník a halda sú miesta, kde dochádza k dynamickému prideľovaniu pamäte: keď vytvoríte premennú pre funkciu, keď vytvoríte inštanciu triedy, keď odošlete parametre funkcii a použijete / odovzdáte jej výsledok hodnota.
Čo je to Stack?
Keď deklarujete premennú vo funkcii, pamäť potrebná na zadržanie premennej sa pridelí zo zásobníka. Jednoducho napíšete „var x: integer“, použijete vo svojej funkcii „x“ a keď funkcia skončí, nestaráte sa o pridelenie pamäte ani uvoľnenie. Keď premenná zmizne z rozsahu (kód opustí funkciu), pamäť, ktorá bola prijatá do zásobníka, je uvoľnená.
Pamäť zásobníka sa prideľuje dynamicky pomocou prístupu LIFO ("last in first out").
v Programy Delphi, pamäť zásobníka používa
- Premenné lokálnej rutiny (metóda, postup, funkcia).
- Rutinné parametre a typy návratov.
- Funkcia rozhrania Windows API hovory.
- Záznamy (z tohto dôvodu nemusíte explicitne vytvárať inštancie typu záznamu).
Nemusíte explicitne uvoľňovať pamäť v zásobníku, pretože táto pamäť je pre vás automaticky magicky pridelená, keď napríklad deklarujete miestnu premennú pre funkciu. Keď funkcia skončí (niekedy aj predtým kvôli optimalizácii kompilátora Delphi), pamäť pre premennú bude automaticky magicky uvoľnená.
Veľkosť pamäte zásobníka je predvolene dostatočne veľká pre vaše (rovnako zložité) programy Delphi. Hodnoty „Maximálna veľkosť zásobníka“ a „Minimálna veľkosť zásobníka“ vo voľbách Linker pre váš projekt určujú predvolené hodnoty - v 99,99% by ste to nemuseli meniť.
Zásobník si predstavte ako hromadu pamäťových blokov. Keď deklarujete / použijete miestnu premennú, správca pamäte Delphi vyberie blok zhora, použije ho a ak už nie je potrebný, vráti sa späť do zásobníka.
Keď sa zo zásobníka použije pamäť lokálnej premennej, lokálne premenné sa pri deklarovaní neinicializujú. Deklarujte premennú "var x: celé číslo" v niektorej funkcii a skúste prečítať hodnotu, keď vstúpite do funkcie - x bude mať nejakú "divnú" nenulovú hodnotu. Takže vždy, keď si prečítate ich hodnotu, vždy inicializujte (alebo nastavte hodnotu) do svojich miestnych premenných.
Kvôli LIFO sú operácie zásobníka (alokácie pamäte) rýchle, pretože na správu zásobníka je potrebných iba niekoľko operácií (push, pop).
Čo je halda?
Halda je oblasťou pamäte, v ktorej je uložená dynamicky alokovaná pamäť. Keď vytvoríte inštanciu triedy, pamäť sa pridelí z haldy.
V programoch Delphi používa pamäť haldy / kedy
- Vytvorenie inštancie triedy.
- Vytváranie a zmena veľkosti dynamických polí.
- Explicitné alokovanie pamäte pomocou GetMem, FreeMem, New and Dispose ().
- Použitie reťazcov, variantov a rozhraní ANSI / wide / Unicode (spravované automaticky spoločnosťou Delphi).
Hromadná pamäť nemá žiadne pekné rozloženie, kde by sa vyskytol nejaký poriadok alokuje bloky pamäte. Halda vyzerá ako plechovka guličiek. Pridelenie pamäte z haldy je náhodné, blok odtiaľto ako blok odtiaľto. Operácie haldy sú teda o niečo pomalšie ako operácie v zásobníku.
Keď požiadate o nový blok pamäte (t. J. Vytvoriť inštanciu triedy), správca pamäte Delphi to zvládne za vás: získate nový alebo použitý a vyradený blok.
Halda pozostáva zo všetkej virtuálnej pamäte (RAM a miesto na disku).
Manuálne pridelenie pamäte
Teraz, keď je všetko o pamäti jasné, môžete bezpečne (vo väčšine prípadov) ignorovať vyššie uvedené a jednoducho pokračovať v písaní programov Delphi, ako ste to urobili včera.
Samozrejme by ste si mali byť vedomí, kedy a ako ručne alokovať / uvoľniť pamäť.
"EStackOverflow" (od začiatku článku) bol zvýšený, pretože pri každom volaní na DoStackOverflow bol použitý nový segment pamäte zo zásobníka a zásobník má obmedzenia. Tak jednoduché.