Izpratne par atmiņas piešķiršanu Delphi

Rokas, kas tur datora cieto disku

Getty Images/Daniels Sambrauss





Vienreiz izsauciet funkciju DoStackOverflow no savu kodu un jūs saņemsiet EStackOverflow Delphi radīja kļūdu ar ziņojumu 'steka pārpilde'.

|_+_||_+_|
|_+_|
|_+_|
|_+_|

Kas ir šī 'kaudze' un kāpēc tur ir pārpilde, izmantojot iepriekš minēto kodu?



Tātad funkcija DoStackOverflow rekursīvi izsauc sevi — bez “izejas stratēģijas” — tā tikai turpina griezties un nekad neiziet.

Ātrs labojums ir novērst acīmredzamo kļūdu un nodrošināt, ka funkcija kādā brīdī pastāv (lai jūsu kods varētu turpināt izpildi no vietas, kur esat izsaucis funkciju).



Jūs virzāties tālāk un nekad neatskatāties atpakaļ, nerūpējoties par kļūdu/izņēmumu, jo tā tagad ir atrisināta.

Tomēr jautājums paliek: kas ir šī kaudze un kāpēc ir pārpilde ?

Atmiņa jūsu Delphi lietojumprogrammās

Uzsākot programmēšanu Delphi, var rasties tāda kļūda kā iepriekš, jūs to atrisinātu un turpinātu. Tas ir saistīts ar atmiņas piešķiršanu. Lielāko daļu laika jums būtu vienalga par atmiņas piešķiršanu tik ilgi, cik jūs bezmaksas to, ko jūs izveidojat .

Iegūstot vairāk pieredzes Delphi, jūs sākat veidot savas klases, izveidot tās, rūpēties par atmiņas pārvaldību un tamlīdzīgi.



Jūs nokļūsit līdz vietai, kur palīdzības sadaļā lasīsit kaut ko līdzīgu Vietējie mainīgie (deklarēti procedūrās un funkcijās) atrodas lietojumprogrammā kaudze .' un arī Klases ir atsauces veidi, tāpēc tās netiek kopētas uzdevumā, tās tiek nodotas pēc atsauces, un tās tiek piešķirtas kaudze .

Tātad, kas ir “kaudze” un kas ir “kaudze”?



Kaudze pret kaudzi

Lietojumprogrammas palaišana operētājsistēmā Windows , atmiņā ir trīs apgabali, kuros jūsu lietojumprogramma glabā datus: globālā atmiņa, kaudze un kaudze.

Globālie mainīgie (to vērtības/dati) tiek saglabāti globālajā atmiņā. Atmiņu globālajiem mainīgajiem rezervē jūsu lietojumprogramma, kad programma tiek startēta, un tā paliek piešķirta, līdz programma tiek pārtraukta. Globālo mainīgo atmiņu sauc par “datu segmentu”.



Tā kā globālā atmiņa tiek piešķirta un atbrīvota tikai vienu reizi, kad programma tiek pārtraukta, šajā rakstā mēs par to nerūpējamies.

Stack un kaudze ir vieta, kur notiek dinamiska atmiņas piešķiršana: kad izveidojat mainīgo funkcijai, kad izveidojat klases gadījumu, kad nosūtāt parametrus funkcijai un izmantojat/nododat tās rezultāta vērtību.



Kas ir Stack?

Kad funkcijā deklarējat mainīgo, mainīgā turēšanai nepieciešamā atmiņa tiek piešķirta no steka. Jūs vienkārši ierakstāt 'var x: integer', savā funkcijā izmantojiet 'x', un, kad funkcija iziet, jūs nerūpējas par atmiņas piešķiršanu vai atbrīvošanu. Kad mainīgais iziet ārpus darbības jomas (kods iziet no funkcijas), tiek atbrīvota steka atmiņa.

Steka atmiņa tiek dinamiski piešķirta, izmantojot LIFO (“pēdējais pirmais ārā”) pieeju.

In Delphi programmas , steka atmiņu izmanto

  • Vietējie rutīnas (metode, procedūra, funkcija) mainīgie.
  • Rutīnas parametri un atgriešanas veidi.
  • Windows API funkcijazvani.
  • Ieraksti (šī iemesla dēļ jums nav īpaši jāizveido ieraksta tipa gadījums).

Jums nav skaidri jāatbrīvo steka atmiņa, jo atmiņa tiek automātiski maģiski piešķirta, kad, piemēram, deklarējat funkcijai lokālo mainīgo. Kad funkcija iziet (dažreiz pat pirms tam Delphi kompilatora optimizācijas dēļ), mainīgā atmiņa tiks automātiski maģiski atbrīvota.

Stack atmiņas lielumspēc noklusējuma ir pietiekami liela jūsu (lai arī cik sarežģītas tās ir) Delphi programmām. Vērtības 'Maksimālais skursteņa lielums' un 'Minimālais skursteņa lielums' jūsu projekta Linker opcijās norāda noklusējuma vērtības — 99,99% gadījumā jums tas nav jāmaina.

Padomājiet par kaudzi kā atmiņas bloku kaudzi. Kad deklarējat/lietojat lokālo mainīgo, Delphi atmiņas pārvaldnieks izvēlēsies bloku no augšas, izmantos to un, kad tas vairs nebūs vajadzīgs, tiks atgriezts atpakaļ kaudzē.

Izmantojot lokālo mainīgo atmiņu no steka, vietējie mainīgie netiek inicializēti, kad tie tiek deklarēti. Deklarējiet mainīgo 'var x: integer' kādā funkcijā un vienkārši mēģiniet nolasīt vērtību, kad ievadāt funkciju — x būs kāda 'dīvaina' vērtība, kas nav nulle. Tāpēc vienmēr inicializējiet (vai iestatiet vērtību) vietējiem mainīgajiem, pirms lasāt to vērtību.

Pateicoties LIFO, steka (atmiņas piešķiršanas) darbības ir ātras, jo, lai pārvaldītu steku, ir nepieciešamas tikai dažas darbības (push, pop).

Kas ir kaudze?

Kaudze ir atmiņas apgabals, kurā tiek glabāta dinamiski piešķirtā atmiņa. Kad veidojat klases gadījumu, atmiņa tiek piešķirta no kaudzes.

Delphi programmās kaudzes atmiņu izmanto / kad

  • Klases gadījuma izveide.
  • Dinamisku masīvu izveide un izmēru maiņa.
  • Precīza atmiņas piešķiršana, izmantojot GetMem, FreeMem, New un Dispose().
  • Izmantojot ANSI/wide/unikoda virknes, variantus, interfeisus (automātiski pārvalda Delphi).

Kaudzes atmiņai nav glīta izkārtojuma, kur būtu zināma kārtība atmiņas bloku piešķiršanā. Kaudze izskatās pēc bumbiņu kārbas. Atmiņas piešķiršana no kaudzes ir nejauša — bloks no šejienes, nevis bloks no turienes. Tādējādi kaudzes darbības ir nedaudz lēnākas nekā kaudzes operācijas.

Kad jūs pieprasāt jaunu atmiņas bloku (t.i., izveidojat klases gadījumu), Delphi atmiņas pārvaldnieks to darīs jūsu vietā: jūs saņemsiet jaunu atmiņas bloku vai lietotu un izmestu.

Kaudze sastāv no visas virtuālās atmiņas ( RAM un diska vieta ).

Manuāla atmiņas piešķiršana

Tagad, kad viss par atmiņu ir skaidrs, varat droši (vairumā gadījumu) ignorēt iepriekš minēto un vienkārši turpināt rakstīt Delphi programmas, kā to darījāt vakar.

Protams, jums jāzina, kad un kā manuāli piešķirt/atbrīvot atmiņu.

'EStackOverflow' (no raksta sākuma) tika pacelts, jo ar katru DoStackOverflow izsaukumu tika izmantots jauns atmiņas segments no steka, un stekam ir ierobežojumi. Tik vienkārši.