Atminties paskirstymo „Delphi“ supratimas
Getty Images / Danielis Sambrausas
Vieną kartą iškvieskite funkciją „DoStackOverflow“. jūsų kodas ir tu gausi EStackOverflow klaida, kurią iškėlė Delphi su pranešimu „stack overflow“.
|_+_||_+_||_+_|
|_+_|
|_+_|
Kas tai yra ir kodėl naudojant aukščiau pateiktą kodą yra perpildymas?
Taigi DoStackOverflow funkcija rekursyviai išsikviečia save – be „išėjimo strategijos“ – ji tiesiog sukasi ir niekada neišeina.
Greitas pataisymas yra pašalinti akivaizdžią turimą klaidą ir užtikrinti, kad funkcija tam tikru momentu egzistuoja (kad jūsų kodas galėtų tęstis ten, kur iškvietėte funkciją).
Jūs judate toliau ir niekada nežiūrite atgal, nesirūpindami klaida / išimtimi, kuri dabar yra išspręsta.
Tačiau klausimas išlieka: kas tai yra ir kodėl yra perpildymas ?
Atmintis jūsų Delphi programose
Kai pradėsite programuoti Delphi, galite patirti tokią klaidą kaip aukščiau, ją išspręsite ir judėkite toliau. Tai susiję su atminties paskirstymu. Dažniausiai jums nerūpi atminties paskirstymas tol, kol jūs nemokamai ką sukuriate .
Kai įgyjate daugiau Delphi patirties, pradedate kurti savo klases, jas kurti, rūpinatės atminties valdymu ir panašiai.
Pasieksite tašką, kai žinyne skaitysite kažką panašaus „Vietiniai kintamieji (deklaruojami procedūrose ir funkcijose) yra taikomojoje programoje krūva .' ir taip pat Klasės yra orientaciniai tipai, todėl jos nėra kopijuojamos atliekant užduotį, perduodamos remiantis nuoroda ir paskirstomos krūva .
Taigi, kas yra „stack“ ir kas yra „krūva“?
Stack vs Heap
Programos paleidimas sistemoje „Windows“. , atmintyje yra trys sritys, kuriose jūsų programa saugo duomenis: visuotinė atmintis, krūva ir krūva.
Globalūs kintamieji (jų reikšmės/duomenys) saugomi globalioje atmintyje. Visuotiniams kintamiesiems atmintį rezervuoja jūsų programa, kai programa paleidžiama, ir lieka paskirstyta tol, kol programa baigiasi. Globalių kintamųjų atmintis vadinama „duomenų segmentu“.
Kadangi pasaulinė atmintis paskirstoma ir atlaisvinama tik vieną kartą pasibaigus programai, šiame straipsnyje mes tuo nesirūpiname.
Stack ir heap yra vieta, kur vyksta dinaminis atminties paskirstymas: kai kuriate funkcijos kintamąjį, kai sukuriate klasės egzempliorių, kai siunčiate parametrus funkcijai ir naudojate / perduodate jos rezultato reikšmę.
Kas yra Stack?
Kai deklaruojate kintamąjį funkcijos viduje, atmintis, reikalinga kintamajam laikyti, yra paskirstoma iš kamino. Jūs tiesiog rašote „var x: integer“, savo funkcijoje naudojate „x“, o kai funkcija išeina, jums nerūpi nei atminties paskirstymas, nei atlaisvinimas. Kai kintamasis nepatenka į taikymo sritį (kodas išeina iš funkcijos), atmintis, kuri buvo paimta iš kamino, atlaisvinama.
Stacko atmintis paskirstoma dinamiškai, naudojant LIFO („paskutinis pirmas išeinantis“) metodą.
Į Delphi programas , kamino atmintį naudoja
- Vietiniai įprastiniai (metodas, procedūra, funkcija) kintamieji.
- Įprasti parametrai ir grąžinimo tipai.
- Windows API funkcijaskambučių.
- Įrašai (todėl jums nereikia aiškiai sukurti įrašo tipo egzemplioriaus).
Nereikia aiškiai atlaisvinti krūvos atminties, nes atmintis automatiškai magiškai paskirstoma jums, kai, pavyzdžiui, deklaruojate funkcijos vietinį kintamąjį. Kai funkcija išjungiama (kartais net anksčiau dėl Delphi kompiliatoriaus optimizavimo), kintamojo atmintis bus automatiškai atlaisvinta.
Stack atminties dydispagal numatytuosius nustatymus yra pakankamai didelis jūsų (kad ir kokios sudėtingos jos būtų) Delphi programoms. Jūsų projekto Linker parinkčių vertės „Maksimalus krūvos dydis“ ir „Mažiausias krūvos dydis“ nurodo numatytąsias reikšmes – 99,99 % jums nereikės to keisti.
Pagalvokite apie krūvą kaip apie atminties blokų krūvą. Kai deklaruosite / naudosite vietinį kintamąjį, „Delphi“ atminties tvarkyklė pasirinks bloką iš viršaus, naudos jį ir, kai nebereikia, grąžins atgal į krūvą.
Naudojant vietinę kintamųjų atmintį iš kamino, vietiniai kintamieji nėra inicijuojami, kai jie deklaruojami. Paskelbkite kintamąjį „var x: integer“ kurioje nors funkcijoje ir tiesiog pabandykite perskaityti reikšmę, kai įvesite funkciją – x turės „keistą“ reikšmę, kuri nėra nulis. Taigi, visada inicijuokite (arba nustatykite reikšmę) vietiniams kintamiesiems prieš skaitydami jų reikšmę.
Dėl LIFO dėklo (atminties paskirstymo) operacijos yra greitos, nes norint tvarkyti krūvą reikia tik kelių operacijų (push, pop).
Kas yra Krūva?
Krūva yra atminties sritis, kurioje saugoma dinamiškai paskirstyta atmintis. Kai kuriate klasės egzempliorių, atmintis paskirstoma iš krūvos.
Delphi programose krūvos atmintį naudoja / kada
- Kuriant klasės egzempliorių.
- Dinaminių masyvų kūrimas ir dydžio keitimas.
- Aiškus atminties paskirstymas naudojant GetMem, FreeMem, New ir Dispose().
- Naudojant ANSI/wide/Unicode eilutes, variantus, sąsajas (automatiškai valdomas Delphi).
Krūvos atmintis neturi gražaus išdėstymo, kur būtų tam tikra tvarka, paskirstant atminties blokus. Krūva atrodo kaip rutuliukų skardinė. Atminties paskirstymas iš krūvos yra atsitiktinis, blokas iš čia nei blokas iš ten. Taigi krūvos operacijos yra šiek tiek lėtesnės nei atliekamos krūvoje.
Kai paprašysite naujo atminties bloko (t. y. sukursite klasės egzempliorių), Delphi atminties tvarkyklė sutvarkys tai už jus: gausite naują atminties bloką arba panaudotą ir išmestą.
Krūva susideda iš visos virtualios atminties ( RAM ir vietos diske ).
Rankinis atminties paskirstymas
Dabar, kai viskas apie atmintį aišku, galite saugiai (daugeliu atvejų) nekreipti dėmesio į tai, kas išdėstyta aukščiau, ir tiesiog tęsti „Delphi“ programų rašymą, kaip darėte vakar.
Žinoma, turėtumėte žinoti, kada ir kaip rankiniu būdu paskirstyti / atlaisvinti atmintį.
„EStackOverflow“ (nuo straipsnio pradžios) buvo iškeltas, nes su kiekvienu DoStackOverflow iškvietimu buvo naudojamas naujas atminties segmentas iš kamino ir dėklas turi apribojimų. Kaip paprasta.