Vienu reizi izsauciet funkciju "DoStackOverflow" savu kodu un jūs iegūsit EStackOverflow kļūda, ko izraisīja Delfi ar ziņojumu "kaudze pārpildīta".
funkcija DoStackOverflow: vesels skaitlis;
sākt
rezultāts: = 1 + DoStackOverflow;
beigas;
Kas ir šī "kaudze" un kāpēc tur, izmantojot iepriekš norādīto kodu, ir pārpildījums?
Tātad, funkcija DoStackOverflow sevi rekursīvi sauc par sevi - bez “izejas stratēģijas” - tā tikai turpina griezties un nekad neiziet.
Ātri labojot, jūs to izdarītu, ir jānoņem acīmredzamā kļūda un jāpārliecinās, ka funkcija kādā brīdī pastāv (lai jūsu kods varētu turpināt izpildīt no vietas, kur esat izsaucis funkciju).
Jūs virzāties tālāk, un jūs nekad neatskatīsities, nerūpējoties par kļūdu / izņēmumu, jo tas tagad ir atrisināts.
Tomēr joprojām paliek jautājums: kas ir šī kaudze un kāpēc notiek pārpilde?
Atmiņa jūsu Delphi lietojumprogrammās
Sākot programmēšanu Delfā, jūs varētu piedzīvot tādas kļūdas kā iepriekš, jūs to atrisinātu un pārietu tālāk. Šis ir saistīts ar atmiņas piešķiršanu. Lielāko daļu laika jums nerūpētos par atmiņas piešķiršanu, kamēr vien jūs
atbrīvojiet to, ko jūs izveidojat.Iegūstot lielāku pieredzi Delphi, jūs sākat veidot savas nodarbības, tās vadīt, rūpēties par atmiņas pārvaldību un tamlīdzīgi.
Jūs nokļūsit vietā, 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 tipi, tāpēc tās netiek kopētas piešķirot, tās tiek nodotas ar atsauci un tiek iedalītas klasē kaudzes.
Tātad, kas ir "kaudze" un kas ir "kaudze"?
Kaudze vs. Kaudzes
Lietojumprogrammas palaišana operētājsistēmā Windows, atmiņā ir trīs zonas, kurās jūsu lietojumprogramma glabā datus: globālā atmiņa, kaudze un kaudze.
Globālie mainīgie (to vērtības / dati) tiek glabāti globālajā atmiņā. Globālo mainīgo atmiņu jūsu programma rezervē, startējot programmu, un tai tiek piešķirta vieta, līdz jūsu programma beidzas. Globālo mainīgo atmiņu sauc par "datu segmentu".
Tā kā globālā atmiņa tikai vienu reizi tiek piešķirta un atbrīvota programmas pārtraukšanas laikā, mums šajā rakstā tas nerūp.
Kaudze un kaudze ir vieta, kur notiek dinamiskā atmiņas iedalīšana: izveidojot funkcijai mainīgo, kad izveidojat klases gadījumu, kad funkcijai sūtāt parametrus un izmantojat / nododat tās rezultātu vērtību.
Kas ir steks?
Kad jūs deklarējat mainīgo funkcijas iekšpusē, no kaudzes tiek atvēlēta atmiņa, kas nepieciešama mainīgā turēšanai. Jūs vienkārši rakstāt "var x: vesels skaitlis", savā funkcijā izmantojat "x", un, kad funkcija iziet, jums nav jārūpējas par atmiņas piešķiršanu vai atbrīvošanu. Kad mainīgais iziet no darbības jomas (kods iziet no funkcijas), tiek atbrīvota atmiņa, kas tika uzņemta kaudzē.
Steka atmiņa tiek piešķirta dinamiski, izmantojot LIFO ("pēdējais pirmais ārā") pieeju.
Iekšā Delphi programmas, kaudze atmiņu izmanto
- Vietējie ikdienas (metodes, procedūras, funkcijas) mainīgie.
- Kārtējie parametri un atgriešanās veidi.
- Windows API funkcija zvani.
- Ieraksti (tas ir iemesls, kāpēc jums nav tieši jāizveido ierakstu veida gadījumi).
Jums nav skaidri jāatbrīvo kaudzē esošā atmiņa, jo atmiņa jums tiek automātiski piešķirta, kad, piemēram, deklarējat funkciju kā lokālu mainīgo. Kad funkcija iziet (dažreiz pat pirms Delphi kompilatora optimizācijas) mainīgā atmiņa tiks automātiski atbrīvota.
Atmiņas lielums pēc noklusējuma ir pietiekami liels, lai jūsu (tik sarežģītas kā tās būtu) Delphi programmas. Projekta Linker opcijās esošajās vērtībās "Maksimālais kaudzes lielums" un "Minimālais kaudzes lielums" ir norādītas noklusējuma vērtības - 99.99% jums tas nav jāmaina.
Domājiet par kaudzīti kā atmiņas bloku kaudzi. Kad jūs deklarējat / izmantojat vietējo mainīgo, Delphi atmiņas pārvaldnieks izvēlēsies bloku no augšas, izmantos to, un, kad tas vairs nebūs vajadzīgs, tas tiks atgriezts atpakaļ kaudzī.
Ja no kaudzītes tiek izmantota vietējā mainīgā atmiņa, vietējie mainīgie netiek deklarēti. Deklarējiet mainīgo "var x: integer" kādā funkcijā un vienkārši mēģiniet nolasīt vērtību, ievadot 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.
Sakarā ar LIFO, steka (atmiņas iedalīšana) operācijas ir ātras, jo kaudzes pārvaldīšanai ir vajadzīgas tikai dažas operācijas (push, pop).
Kas ir kaudzes?
Kaudze ir atmiņas reģions, kurā tiek glabāta dinamiski iedalītā atmiņa. Izveidojot klases gadījumu, atmiņa tiek piešķirta no kaudzes.
Delphi programmās kaudzes atmiņu izmanto / kad
- Klases instances izveidošana.
- Dinamisko masīvu izveidošana un mainīšana.
- Nepārprotami atmiņas piešķiršana, izmantojot GetMem, FreeMem, New un Dispose ().
- Izmantojot ANSI / platas / Unicode virknes, variantus, saskarnes (automātiski pārvalda Delphi).
Kaudzes atmiņai nav jauka izkārtojuma, kur varētu būt kāda kārtība, kas piešķir atmiņas blokus. Kaudzes izskatās kā bumbiņu bundža. Atmiņas piešķiršana no kaudzes ir nejauša, bloks no šejienes, nevis bloks no turienes. Tādējādi kaudzes operācijas ir nedaudz lēnākas nekā kaudze.
Kad jūs lūgsit jaunu atmiņas bloku (t.i., izveidosit klases instanci), Delphi atmiņas pārvaldnieks par to atbildēs jums: jūs iegūsit jaunu atmiņas bloku vai lietotu un izmestu.
Kaudze sastāv no visas virtuālās atmiņas (RAM un diska vieta).
Atmiņas manuāla piešķiršana
Tagad, kad viss atmiņā ir skaidrs, varat droši (vairumā gadījumu) ignorēt iepriekšminēto un vienkārši turpināt rakstīt Delphi programmas, kā jūs darījāt vakar.
Protams, jums jāzina, kad un kā manuāli sadalīt / atbrīvot atmiņu.
"EStackOverflow" (no raksta sākuma) tika izvirzīts, jo ar katru zvanu uz DoStackOverflow no kaudzītes tika izmantots jauns atmiņas segments, un kaudzei ir ierobežojumi. Tik vienkārši.