V knihách o programovacích jazykoch sa vysvetľuje, že hodnotové typy sa vytvárajú na zásobníku a referenčné typy sa vytvárajú na hromade, pričom sa nevysvetľuje, čo tieto dve veci znamenajú. Nečítal som jasné vysvetlenie. Chápem, čo je to zásobník. Ale,
Sklad:
Heap:
delete
, delete[]
alebo free
.new
, resp. príkazu malloc
.Príklad:
int foo()
{
char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack).
bool b = true; // Allocated on the stack.
if(b)
{
//Create 500 bytes on the stack
char buffer[500];
//Create 500 bytes on the heap
pBuffer = new char[500];
}//<-- buffer is deallocated here, pBuffer is not
}//<--- oops there's a memory leak, I should have called delete[] pBuffer;
Zásobník Pri volaní funkcie sa argumenty tejto funkcie plus niektoré ďalšie režijné náklady umiestnia na zásobník. Ukladajú sa tam aj niektoré informácie (napríklad kam sa má funkcia vrátiť). Keď deklarujete premennú vo vnútri funkcie, táto premenná je tiež alokovaná na zásobníku.
Dealokácia zásobníka je pomerne jednoduchá, pretože sa vždy dealokuje v opačnom poradí, ako sa alokuje. Veci zo zásobníka sa pridávajú pri vstupe do funkcií, príslušné údaje sa odstraňujú pri výstupe z nich. To znamená, že máte tendenciu zostať v malej oblasti zásobníka, pokiaľ nevoláte veľa funkcií, ktoré volajú veľa iných funkcií (alebo nevytvárate rekurzívne riešenie).
Hromada Hromada je všeobecný názov pre miesto, kam umiestňujete údaje, ktoré vytvárate za chodu. Ak ne'viete, koľko vesmírnych lodí váš program vytvorí, pravdepodobne použijete operátor new (alebo malloc alebo ekvivalentný operátor) na vytvorenie každej vesmírnej lode. Táto alokácia sa bude chvíľu zdržiavať, takže je pravdepodobné, že veci uvoľníme v inom poradí, ako sme ich vytvorili.
Hromada je teda oveľa zložitejšia, pretože nakoniec sa v nej striedajú oblasti pamäte, ktoré sú nevyužité, s kúskami, ktoré sú - pamäť sa fragmentuje. Nájsť voľnú pamäť potrebnej veľkosti je zložitý problém. Preto by sme sa mali halde vyhýbať (hoci sa stále často používa).
Implementácia Implementácia zásobníka aj haldy zvyčajne závisí od bežiaceho prostredia/operačného systému. Hry a iné aplikácie, ktoré sú kritické na výkon, si často vytvárajú vlastné pamäťové riešenia, ktoré si z haldy berú veľký kus pamäte a potom ju interne rozdeľujú, aby sa nemuseli spoliehať na operačný systém.
To je praktické len vtedy, ak sa využitie pamäte výrazne líši od normy - t. j. v prípade hier, kde načítate úroveň v jednej obrovskej operácii a môžete ju celú vyhodiť v ďalšej obrovskej operácii.
Fyzické umiestnenie v pamäti Toto je menej dôležité, ako si myslíte, pretože technológia nazývaná virtuálna pamäť spôsobuje, že váš program si myslí, že má prístup k určitej adrese, pričom fyzické údaje sú niekde inde (dokonca aj na pevnom disku!). Adresy, ktoré získavate pre zásobník, sú v rastúcom poradí, ako sa váš strom volaní prehlbuje. Adresy pre haldu sú nepredvídateľné (t. j. špecifické pre implimentáciu) a úprimne povedané, nie sú dôležité.
Zásobník je časť pamäte, s ktorou možno manipulovať pomocou niekoľkých kľúčových inštrukcií jazyka assembleru, ako sú 'pop' (odstránenie a vrátenie hodnoty zo zásobníka) a 'push' (vloženie hodnoty do zásobníka), ale aj call (volanie podprogramu - pri tejto inštrukcii sa adresa vráti na zásobník) a return (návrat z podprogramu - pri tejto inštrukcii sa adresa vyskočí zo zásobníka a skočí sa na ňu). Je to oblasť pamäte pod registrom ukazovateľa zásobníka, ktorú možno nastaviť podľa potreby. Zásobník sa používa aj na odovzdávanie argumentov podprogramom a tiež na uchovanie hodnôt v registroch pred volaním podprogramov.
Hromada je časť pamäte, ktorú aplikácii poskytuje operačný systém, zvyčajne prostredníctvom volania syscall, napríklad malloc. V moderných operačných systémoch je táto pamäť súborom stránok, ku ktorým má prístup len volajúci proces.
Veľkosť zásobníka sa určuje počas behu a po spustení programu sa spravidla nezväčšuje. V programe v jazyku C musí byť zásobník dostatočne veľký, aby sa doň zmestili všetky premenné deklarované v rámci každej funkcie. Zásobník sa dynamicky zväčšuje podľa potreby, ale v konečnom dôsledku volanie vykonáva operačný systém (často zväčší zásobník o viac, ako je hodnota požadovaná mallocom, aby sa aspoň niektoré budúce malloc'y nemuseli vracať do jadra, aby získali viac pamäte. Toto správanie sa často dá prispôsobiť)
Keďže ste zásobník alokovali pred spustením programu, nikdy nemusíte mallocovať pred tým, ako môžete zásobník použiť, takže'to je mierna výhoda. V praxi je'veľmi ťažké predvídať, čo bude rýchle a čo pomalé v moderných operačných systémoch, ktoré majú subsystémy virtuálnej pamäte, pretože to, ako sú stránky implementované a kde sú uložené, je implementačný detail.