Înțelegerea alocării memoriei în Delphi

Apelați funcția „DoStackOverflow” o dată de la codul dvs. și veți primi EStackOverflow eroare ridicată de Delphi cu mesajul „overflow stack”.


 funcţie DoStackOverflow: număr întreg;

începe

 rezultat: = 1 + DoStackOverflow;

Sfârșit;

Ce este această „stivă” și de ce există o revărsare acolo folosind codul de mai sus?

Deci, funcția DoStackOverflow se numește recursiv - fără o „strategie de ieșire” - ea continuă să se rotească și nu iese niciodată.

O soluție rapidă, ai face, este să ștergi erorile evidente pe care le ai și să te asiguri că funcția există la un moment dat (astfel încât codul tău să poată continua să execute de unde ai apelat funcția).

Continuați și nu vă uitați niciodată înapoi, fără să vă preocupați de eroare / excepție, așa cum este acum rezolvată.

Cu toate acestea, rămâne întrebarea: ce este această stivă și de ce există un preaplin?

Memorie în aplicațiile dvs. Delphi

Când începeți programarea în Delphi, s-ar putea să întâmpinați o eroare ca cea de mai sus, o veți rezolva și continuați. Acesta este legat de alocarea memoriei. De cele mai multe ori nu ți-ar păsa de alocarea memoriei atâta timp cât vei elibera ceea ce creezi.

Pe măsură ce câștigi mai multă experiență în Delphi, începi să-ți creezi propriile clase, să le instantanezi, să le pese de gestionarea memoriei și deopotrivă.

Veți ajunge la punctul în care veți citi, în ajutor, ceva de genul "Variabilele locale (declarate în proceduri și funcții) se află în aplicația grămadă." Si deasemenea Clasele sunt tipuri de referință, deci nu sunt copiate la atribuire, sunt trecute prin referință și sunt alocate pe morman.

Deci, ce este „stivă” și ce este „grămadă”?

Stack vs. Heap

Rulând aplicația pe Windows, există trei zone în memorie în care aplicația dvs. stochează date: memorie globală, heap și stack.

Variabilele globale (valorile / datele lor) sunt stocate în memoria globală. Memoria pentru variabilele globale este rezervată de aplicația dvs. atunci când programul începe și rămâne alocat până la încheierea programului. Memoria pentru variabilele globale se numește "segment de date".

Deoarece memoria globală este alocată și eliberată o singură dată la terminarea programului, în acest articol nu ne pasă.

Stack și heap sunt locurile în care are loc alocarea dinamică a memoriei: când creezi o variabilă pentru o funcție, când creezi o instanță a unei clase atunci când trimiteți parametrii unei funcții și utilizați / treceți valoarea rezultatului acesteia.

Ce este Stack?

Când declarați o variabilă în interiorul unei funcții, memoria necesară pentru a ține variabila este alocată din stivă. Pur și simplu scrieți „var x: integer”, folosiți „x” în funcția dvs., iar când funcția iese, nu vă pasă de alocarea de memorie și nici de eliberarea. Când variabila iese din raza de acțiune (codul iese din funcție), memoria care a fost luată pe stivă este eliberată.

Memoria de stivă este alocată dinamic folosind abordarea LIFO („ultimul în primul ieșire”).

În programele Delphi, memoria de stivă este folosită de

  • Variabilele de rutină locală (metodă, procedură, funcție).
  • Parametri de rutină și tipuri de retur.
  • Funcțiile API de apeluri Windows.
  • Înregistrări (acesta este motivul pentru care nu trebuie să creați explicit o instanță de tip înregistrare).

Nu trebuie să eliberați explicit memoria din stivă, deoarece memoria este alocată automat pentru dvs. atunci când, de exemplu, declarați o variabilă locală unei funcții. Când funcția iese (uneori chiar înainte ca urmare a optimizării Delphi a compilatorului), memoria variabilei va fi eliberată automat.

În mod implicit, dimensiunea stivei de memorie este suficient de mare pentru programele dvs. Delphi (la fel de complexe pe care le sunt). Valorile „Dimensiunea maximă a stivei” și „Dimensiunea minimă a stivei” din opțiunile Linker pentru proiectul dvs. specifică valorile implicite - în 99,99% nu va trebui să modificați acest lucru.

Gândiți-vă la o stivă ca la o grămadă de blocuri de memorie. Când declarați / utilizați o variabilă locală, managerul de memorie Delphi va alege blocul din partea de sus, îl va folosi, iar atunci când nu va mai fi nevoie, va fi returnat înapoi la stivă.

Având memoria variabilă locală folosită din stivă, variabilele locale nu sunt inițializate atunci când sunt declarate. Declarați o variabilă "var x: integer" într-o anumită funcție și încercați doar să citiți valoarea atunci când introduceți funcția - x va avea o valoare "ciudată" non-zero. Deci, inițializați întotdeauna (sau setați valoarea) la variabilele dvs. locale înainte de a le citi valoarea.

Datorită LIFO, operațiile de stivuire (alocarea memoriei) sunt rapide, deoarece doar câteva operații (push, pop) sunt necesare pentru a gestiona o stivă.

Ce este Heap?

Un morman este o regiune a memoriei în care este stocată memoria alocată dinamic. Când creați o instanță a unei clase, memoria este alocată din grup.

În programele Delphi, memoria heap este folosită de / când

  • Crearea unei instanțe a unei clase.
  • Crearea și redimensionarea tablourilor dinamice.
  • Alocarea explicită a memoriei folosind GetMem, FreeMem, New și Eliminați ().
  • Folosind șiruri ANSI / wide / Unicode, variante, interfețe (gestionate automat de Delphi).

Memoria Heap nu are un aspect frumos în care ar exista o anumită ordine de alocare a blocurilor de memorie. Mormanul arată ca o cutie de marmură. Alocarea memoriei din grămadă este întâmplătoare, un bloc de aici decât un bloc de acolo. Astfel, operațiunile de montaj sunt puțin mai lente decât cele de pe stivă.

Când solicitați un nou bloc de memorie (de exemplu, creați o instanță a unei clase), managerul de memorie Delphi va gestiona acest lucru pentru dvs.: veți primi un bloc de memorie nou sau unul folosit și aruncat.

Mormonul este format din toată memoria virtuală (RAM și spațiu pe disc).

Alocarea manuală a memoriei

Acum că toată memoria este limpede, puteți ignora în siguranță (în majoritatea cazurilor) cele de mai sus și pur și simplu continuați să scrieți programe Delphi așa cum ați făcut ieri.

Desigur, ar trebui să știți când și cum să alocați manual / memoria liberă.

„EStackOverflow” (de la începutul articolului) a fost ridicat, deoarece cu fiecare apel către DoStackOverflow, un nou segment de memorie a fost utilizat din stivă și stiva are limitări. Simplu ca buna ziua.