Krūva vs. Stack for Delphi Developers

Paskambinkite funkcijai „DoStackOverflow“ vieną kartą nuo jūsų kodas ir gausite „EStackOverflow“ klaida, kurią iškėlė Delphi pranešime „kamino perpildymas“.


funkcija „DoStackOverflow“: sveikasis skaičius;

prasideda

 rezultatas: = 1 + „DoStackOverflow“;

galas;

Kas yra tas „kaminas“ ir kodėl ten yra perpildymas naudojant aukščiau esantį kodą?

Taigi, „DoStackOverflow“ funkcija rekursyviai vadina save - be „išėjimo strategijos“ - ji tiesiog sukasi ir niekada neišeina.

Greitas pataisymas, kurį jūs padarytumėte, yra išvalyti akivaizdžią klaidą, kurią turite, ir įsitikinkite, kad funkcija tam tikru metu egzistuoja (taigi jūsų kodas gali būti vykdomas toliau ten, kur jūs pakvietėte funkciją).

Jūs judate toliau ir niekada nežiūrite atgal, nesirūpindami klaida / išimtimi, nes ji dabar išspręsta.

Vis dėlto lieka klausimas: kas yra tas kaminas ir kodėl ten yra perpildymas??

Atmintis jūsų „Delphi“ programose

Pradėjus programuoti „Delphi“, gali atsirasti tokių klaidų, kaip aukščiau, jas išspręsite ir judėsite toliau. Tai yra susiję su atminties paskirstymu. Dauguma laiko jums nerūpėtų atminties paskirstymas tol, kol jūs

instagram viewer
atlaisvink tai, ką sukūrei.

Įgaudami daugiau patirties „Delphi“, jūs pradedate kurti savo užsiėmimus, juos konsultuojate, rūpinatės atminties valdymu ir panašiai.

Jūs pateksite į tašką, kuriame „Žinyne“ perskaitysite kažką panašaus "Vietiniai kintamieji (deklaruojami pagal procedūras ir funkcijas) yra programoje kamino." ir taip pat Klasės yra referenciniai tipai, todėl jos nekopijuojamos priskiriant užduotis, jos perduodamos kaip nuorodos ir paskirstomos krūva.

Taigi, kas yra „krūva“ ir kas yra „krūva“?

Stack vs. Krūva

Paleiskite savo programą „Windows“, atmintyje yra trys sritys, kuriose jūsų programa saugo duomenis: visuotinė atmintis, krūva ir krūva.

Visuotiniai kintamieji (jų vertės / duomenys) saugomi globalioje atmintyje. Visuotinių kintamųjų atmintį jūsų programa rezervuoja paleidus programą ir ji skiriama tol, kol jūsų programa baigsis. Visuotinių kintamųjų atmintis vadinama „duomenų segmentu“.

Kadangi pasaulinė atmintis yra paskirta ir išlaisvinta tik vieną kartą baigiant programą, mums tai nerūpi šiame straipsnyje.

Rinkinys ir krūva, kur vyksta dinaminis atminties paskirstymas: kai sukuriate funkcijos kintamąjį, kai sukuriate klasės egzempliorių, kai siunčiate parametrus funkcijai ir naudojate / perduodate jos rezultatą vertės.

Kas yra „Stack“?

Kai deklaruojate kintamąjį funkcijos viduje, atmintis, reikalinga kintamajam laikyti, paskirstoma iš krūvos. Jūs tiesiog rašote „var x: integer“, savo funkcijoje naudojate „x“, o kai funkcija išnyksta, jums nerūpi nei atminties paskirstymas, nei atlaisvinimas. Kai kintamasis išeina iš aprėpties (kodas išeina iš funkcijos), atlaisvinta kamino atmintis.

Rietuvės atmintis paskirstoma dinamiškai, naudojant LIFO („paskutinis iš pirmo išėjimo“) metodą.

Į „Delphi“ programos, kamino atmintį naudoja

  • Vietiniai rutinos (metodas, procedūra, funkcija) kintamieji.
  • Įprasti parametrai ir grąžinimo tipai.
  • „Windows API“ funkcija skambučiai.
  • Įrašai (štai kodėl jūs neturite aiškiai kurti įrašo tipo egzempliorių).

Jūs neprivalote aiškiai išlaisvinti krūvos atminties, nes, pvz., Deklaruodami vietinį funkcijos kintamąjį, atmintis automatiškai paskirstoma jums. Kai funkcija baigsis (kartais net anksčiau dėl „Delphi“ kompiliatoriaus optimizavimo), kintamojo atmintis bus automatiškai išlaisvinta.

Paketinės atminties dydis pagal nutylėjimą yra pakankamai didelis jūsų (tiek sudėtingoms, kiek jos yra) „Delphi“ programoms. Projekto „Linker“ parinkčių reikšmės „Maksimalus krūvos dydis“ ir „Mažiausias krūvos dydis“ nurodo numatytąsias vertes - 99,99 proc. Jums nereikės to keisti.

Pagalvokite apie krūvą kaip atminties blokų krūvą. Kai deklaruosite / naudosite vietinį kintamąjį, „Delphi“ atminties tvarkyklė pasirinks bloką iš viršaus, jį naudos, o kai nebereikės, jis bus grąžintas atgal į krūvą.

Naudojant vietinę kintamąją atmintį iš krūvos, deklaruoti vietiniai kintamieji nėra inicijuojami. Kai kuriose funkcijose deklaruokite kintamąjį „var x: integer“ ir tiesiog pabandykite nuskaityti reikšmę, kai įvesite funkciją - x turės „keistą“ nulinę reikšmę. Taigi, prieš pradėdami skaityti jų reikšmę, visada inicijuokite (arba nustatykite vertę) vietiniams kintamiesiems.

Dėl LIFO, krūvos (atminties paskirstymas) operacijos yra greitos, nes norint valdyti krūvą reikia tik kelių operacijų (stumti, pop).

Kas yra krūva?

Krūva yra atminties sritis, kurioje saugoma dinamiškai paskirta atmintis. Kai kuriate klasės egzempliorių, atmintis paskirstoma iš krūvos.

Delphi programose krūvos atmintį naudoja / kada

  • Klasės egzemplioriaus sukūrimas.
  • Dinaminių matricų kūrimas ir dydžio keitimas.
  • Aiškiai paskirstyti atmintį naudojant „GetMem“, „FreeMem“, „New“ ir „Dispose“ ().
  • Naudojant ANSI / plataus / Unicode stygas, variantus, sąsajas (automatiškai valdo Delphi).

Pagrindinė atmintis nėra gražaus išdėstymo, kur būtų tam tikra tvarka paskirstyti atminties blokus. Krūva atrodo kaip skardinė marmurinių. Atminties paskirstymas iš krūvos yra atsitiktinis, blokas iš čia, o ne blokas iš ten. Taigi krūvos operacijos yra šiek tiek lėtesnės nei krūvoje.

Kai paprašysite naujos atminties bloko (t. Y. Sukursite klasės egzempliorių), „Delphi“ atminties tvarkyklė tai padarys už jus: gausite naują atminties bloką arba naudotą ir išmestą.

Krūvą sudaro visa virtualioji atmintis (RAM ir vietos diske).

Rankinis atminties paskirstymas

Dabar, kai viskas apie atmintį yra aiški, galite saugiai (daugeliu atvejų) nekreipti dėmesio į tai, kas pasakyta, ir tiesiog tęsti „Delphi“ programų rašymą, kaip tai padarėte vakar.

Žinoma, jūs turėtumėte žinoti, kada ir kaip neautomatiškai paskirstyti / atlaisvinti atmintį.

„EStackOverflow“ (nuo straipsnio pradžios) buvo iškeltas, nes su kiekvienu skambučiu „DoStackOverflow“ iš rietuvės buvo naudojamas naujas atminties segmentas, o rietuvei yra apribojimų. Kaip paprasta.