La risposta è chiaramente dipendente dalla piattaforma, dipendente dal compilatore e dipendente dalla libreria.
Ma considera che in un processo ci sia uno stack per thread e un numero di heap che il processo richiede ai sistemi (normalmente 1, ma ce ne possono essere di più: un SO può avere API per allocare vari "heap").
Ci sono sistemi operativi che danno a un processo un determinato blocco, in cui l'heap e gli stack sono presi per sottrazione, e i sistemi operativi che danno blocchi distinti al processo, ciascuno dei quali traccia un diverso blocco di memoria fisica.
Su sistemi operativi e processori che implementano la memoria virtuale, lo spazio degli indirizzi del processo viene mappato alla memoria fisica da alcune tabelle puntatore invisibili al processo stesso.
Quando diciamo che lo stack cresce e si restringe stiamo parlando nella "visualizzazione del processo". Nella "vista OS", una pila è solo un blocco che non cresce o si riduce a ogni chiamata / ritorno. è solo più o meno pieno. Quando diventa pieno, deve essere riallocato su un'altra area di memoria fisica con più spazio. Il costo di "riallocazione di uno stack frame" è pesante (non deve avere "buchi" all'interno), quindi molti sistemi operativi non consentono a uno stack di crescere su una dimensione predefinita. Ma l'heap dos non ha bisogno di tale cura: se un blocco heap è pieno, viene aggiunto un altro blocco. Non c'è bisogno di renderlo contiguo. Questa -una piattaforma multipla- dà la percezione (nello "spazio del processo") che una pila è limitata (di solito 4MB o simile) mentre l'heap è "infinito" (e limitato solo dalla memoria fisica o dall'area di swap).