Kutsu toiminto "DoStackOverflow" kerran koodisi ja saat EStackOverflow virhe, jonka Delphi on nostanut ilmoituksella "pino ylivuoto".
toimia DoStackOverflow: kokonaisluku;
alkaa
tulos: = 1 + DoStackOverflow;
end;
Mikä tämä "pino" on ja miksi siellä on ylivuoto yllä mainittua koodia käyttämällä?
Joten DoStackOverflow-toiminto kutsuu itseään rekursiivisesti - ilman "poistumisstrategiaa" - se vain pyörii eikä koskaan poistu.
Nopea korjaus, mitä teet, on poistaa ilmeinen vika ja varmistaa, että toiminto on jossain vaiheessa (jotta koodisi voi jatkaa suorittamista mistä kohdasta olet kutsunut toiminto).
Siirryt eteenpäin etkä koskaan katso taaksepäin, et välitä virheestä / poikkeuksesta, koska se on nyt ratkaistu.
Silti kysymys on edelleen: mikä tämä pino on ja miksi ylivuoto on olemassa?
Muisti Delphi-sovelluksissa
Kun aloitat ohjelmoinnin Delphissä, saatat kohdata virheen, kuten yllä, voit ratkaista sen ja siirtyä eteenpäin. Tämä liittyy muistin allokointiin. Suurin osa ajasta et välitä muistin varaamisesta niin kauan kuin sinä vapauta luomasi.
Kun saat enemmän kokemusta Delphistä, alat luoda omia luokkiasi, ohjata niitä, välittää muistinhallinnasta ja niin edelleen.
Pääset pisteeseen, jossa luet Ohjeessa jotain sellaista "Paikalliset muuttujat (ilmoitettu menettelyjen ja toimintojen sisällä) sijaitsevat sovelluksissa pino." ja myös Luokat ovat viitetyyppejä, joten niitä ei kopioida tehtäessä, ne ohitetaan referenssillä ja ne allokoidaan pino.
Joten mikä on "pino" ja mikä on "kasa"?
Pino vs. Pino
Suorita sovellus Windowsissa, muistissa on kolme aluetta, joille sovelluksesi tallentaa tietoja: globaali muisti, kasa ja pino.
Globaalit muuttujat (niiden arvot / tiedot) tallennetaan globaaliin muistiin. Sovellus varaa globaalien muuttujien muistin ohjelman käynnistyessä, ja se on varattu, kunnes ohjelma päättyy. Globaalien muuttujien muistia kutsutaan "data-segmentiksi".
Koska globaali muisti on varattu ja vapautettu vain kerran ohjelman päättyessä, emme välitä siitä tässä artikkelissa.
Pino ja kasa ovat silloin, kun dynaaminen muistin allokointi tapahtuu: kun luot muuttujan toiminnolle, kun luot luokan esiintymän, kun lähetät parametreja funktiolle ja käytät / välität sen tuloksen arvo.
Mikä on pino?
Kun julistat muuttujan funktion sisällä, muuttujan pitämiseen tarvittava muisti allokoidaan pinosta. Sinun tarvitsee vain kirjoittaa "var x: integer", käyttää "x" toiminnossasi, ja kun toiminto poistuu, et välitä muistin varaamisesta tai vapauttamisesta. Kun muuttuja poistuu laajuudesta (koodi poistuu toiminnosta), pinolle otettu muisti vapautetaan.
Pino muisti allokoidaan dynaamisesti käyttämällä LIFO ("viimeinen ensin ulos") -lähestymistapaa.
Sisään Delphi-ohjelmat, pino-muistia käyttää
- Paikalliset rutiinimuoto (menetelmä, menettely, funktio).
- Rutiininomaiset parametrit ja paluulajit.
- Windows API -toiminto puhelut.
- Tietueet (siksi sinun ei tarvitse nimenomaisesti luoda tietuetyyppistä esiintymää).
Sinun ei tarvitse vapauttaa nimenomaisesti pinon muistia, koska muisti allokoidaan sinulle automaattisesti maagisesti, kun esimerkiksi julistat toiminnolle paikallisen muuttujan. Kun toiminto poistuu (joskus jopa ennen Delphi-kääntäjän optimointia), muuttujan muisti vapautetaan automaattisesti maagisesti.
Pino muistin koko on oletuksena riittävän suuri Delphi-ohjelmillesi (niin monimutkaisia kuin ne ovat). Projektorin Linker-asetusten "Suurin pinokoko" ja "Pienin pinokoko" -arvot määrittävät oletusarvot - 99,99%: ssa sinun ei tarvitse muuttaa tätä.
Ajattele pino kasa muistimohkoja. Kun julistat / käytät paikallista muuttujaa, Delphi memory manager valitsee lohkon ylhäältä, käyttää sitä, ja kun sitä ei enää tarvita, se palautetaan takaisin pinoon.
Kun pinosta käytetään paikallista muuttujaa, paikallisia muuttujia ei alusteta, kun ne ilmoitetaan. Ilmoita muuttuja "var x: integer" jossain funktiossa ja yritä vain lukea arvo, kun syötät funktion - x: lla on jokin "outo" arvo, joka ei ole nolla. Alusta siis (tai aseta arvo) paikallisille muuttujille, ennen kuin luet niiden arvoa.
LIFO: n ansiosta pino (muistin allokointi) -operaatiot ovat nopeita, koska pinon hallintaan tarvitaan vain muutama toiminto (push, pop).
Mikä on kasa?
Kasa on muistialue, johon dynaamisesti varattu muisti tallennetaan. Kun luot luokan esiintymän, muisti varataan kasasta.
Delphi-ohjelmissa kasanmuistia käyttää / milloin
- Luokan ilmentymän luominen.
- Dynaamisten taulukkojen luominen ja koon muuttaminen.
- Muistin allokointi nimenomaisesti käyttämällä GetMem, FreeMem, New ja Dispose () -sovelluksia.
- Käyttämällä ANSI / leveä / Unicode-merkkijonoja, muunnelmia, rajapintoja (Delphin automaattisesti hallinnoima).
Kasa-muistilla ei ole mukavaa asettelua, jossa olisi jonkinlainen järjestys muistimohkojen varaamiseksi. Kasa näyttää tölkkiltä marmoria. Muistin allokointi kasasta on satunnainen, lohko täältä kuin lohko sieltä. Siten kasaoperaatiot ovat hiukan hitaampia kuin pinossa.
Kun pyydät uutta muistimuistia (ts. Luot luokan esiintymän), Delphi-muistinhallinta käsittelee tämän puolestasi: saat uuden tai käytetyn ja heitetyn muistin.
Kasa koostuu kaikesta virtuaalimuistista (RAM ja levytila).
Muistin manuaalinen allokointi
Nyt kun muistista on selvää, voit turvallisesti (useimmissa tapauksissa) sivuuttaa yllä mainitun ja jatkaa Delphi-ohjelmien kirjoittamista kuten eilen.
Tietenkin sinun tulisi olla tietoinen siitä, milloin ja miten muisti manuaalisesti varataan / vapautetaan.
"EStackOverflow" (artikkelin alusta) nostettiin esiin, koska jokaisella DoStackOverflow-puhelulla on käytetty uusi muistisegmentti pinosta ja pinolla on rajoituksia. Niin yksinkertaista.