La pile est la mémoire réservée en tant qu'espace d'échange pour un thread d'exécution. Lorsqu'une fonction est appelée, un bloc est réservé en haut de la pile pour les variables locales et certaines données de gestion. Lorsque cette fonction renvoie, le bloc devient inutilisé et peut être utilisé la prochaine fois qu'une fonction est appelée. La pile est toujours réservée selon un ordre LIFO (dernier entré, premier sorti); le bloc le plus récemment réservé est toujours le prochain bloc à être libéré. Cela rend vraiment simple de suivre la pile; libérer un bloc de la pile ne consiste qu'à ajuster un pointeur.
Le tas est la mémoire réservée pour l'allocation dynamique. Contrairement à la pile, il n'y a aucun schéma imposé pour l'allocation et la libération de blocs depuis le tas; vous pouvez allouer un bloc à tout moment et le libérer à tout moment. Cela rend beaucoup plus complexe de suivre quelles parties du tas sont allouées ou libres à un moment donné; il existe de nombreux allocateurs de tas personnalisés disponibles pour ajuster les performances du tas pour différents modèles d'utilisation.
Chaque thread reçoit une pile, tandis qu'il n'y a généralement qu'un seul tas pour l'application (bien qu'il ne soit pas rare d'avoir plusieurs tas pour différents types d'allocation).
Pour répondre directement à vos questions:
Dans quelle mesure sont-ils contrôlés par le système d'exploitation ou le runtime du langage?
Le système d'exploitation alloue la pile pour chaque thread de niveau système lors de la création du thread. En général, le système d'exploitation est appelé par le runtime du langage pour allouer le tas pour l'application.
Quelle est leur portée?
La pile est attachée à un thread, donc lorsque le thread se termine, la pile est récupérée. Le tas est généralement alloué au démarrage de l'application par le runtime, et est récupéré lorsque l'application (techniquement le processus) se termine.
Qu'est-ce qui détermine la taille de chacun d'eux?
La taille de la pile est définie lors de la création d'un thread. La taille du tas est définie au démarrage de l'application, mais peut augmenter au fur et à mesure que l'espace est nécessaire (l'allocateur demande plus de mémoire au système d'exploitation).
Qu'est-ce qui rend l'un plus rapide?
La pile est plus rapide car le modèle d'accès la rend triviale pour allouer et libérer de la mémoire à partir de celle-ci (un pointeur/entier est simplement incrémenté ou décrémenté), tandis que le tas implique beaucoup plus de complexité dans une allocation ou une libération. De plus, chaque octet de la pile est souvent réutilisé, ce qui signifie qu'il tend à être associé fréquemment au cache du processeur, le rendant très rapide. Un autre inconvénient de performance pour le tas est que le tas, étant principalement une ressource globale, doit généralement être sûr pour le multithreading, c'est-à-dire que chaque allocation et libération doit être - typiquement - synchronisée avec "toutes" les autres accès au tas dans le programme.
Une démonstration claire:
Source de l'image: <a href="http://vikashazrati.wordpress.com/2007/10/01/quicktip-java-basics-stack-and-heap/" rel="noreferrer">vikashazrati.wordpress.com</a>
229 votes
Une explication vraiment bonne peut être trouvée ici Quelle est la différence entre une pile et un tas?
17 votes
Aussi (vraiment) bien: codeproject.com/Articles/76153/… (la partie stack/heap)
18 votes
youtube.com/watch?v=clOUdVDDzIM&spfreload=5
4 votes
Voir aussi Stack Clash. Les remédiations Stack Clash ont affecté certains aspects des variables système et des comportements comme
rlimit_stack
. Voir également Red Hat Problème 14632414 votes
@mattshane Les définitions de la pile et du tas ne dépendent en aucun cas des types de valeur et de référence. En d'autres termes, la pile et le tas peuvent être entièrement définis même si les types de valeur et de référence n'ont jamais existé. De plus, en comprenant les types de valeur et de référence, la pile n'est qu'un détail d'implémentation. Selon Eric Lippert : The Stack Is An Implementation Detail, Part One.
1 votes
Non clair dans les réponses : Pour un environnement d'exécution de langage (par exemple, .NET), il y a une pile par fil d'exécution, pour gérer les appels de méthode/variables locales, et seulement un tas défini pour tous les processus de l'environnement d'exécution. Le tas est supervisé par le ramasse-miettes. Les piles/espaces de tas de l'environnement d'exécution font partie de la mémoire virtuelle contiguë allouée par le système d'exploitation aux processus (lui-même alimenté par des morceaux de RAM physique dans aucun ordre spécifique) sur demande des processus. La confusion autour des "piles" est due à l'existence de nombreux types de "pile" dans un ordinateur, non liés aux piles d'exécution de langage. Une "pile" est simplement une structure de stockage LIFO.
0 votes
Si vous voulez voir une simulation de ce à quoi ressemblent la pile et le tas pendant l'exécution d'un programme C, essayez C Tutor.