Vous voudrez peut-être prendre du recul et voir d'où et pourquoi ces modèles existants viennent. Lorsqu'un processus est créé, on lui donne simplement une zone de stockage plate qui est simplement indexée de 0 à N. Parce que cette zone de stockage (en parlant de RAM ici) est soutenue par un matériel dédié et certains semi-conducteurs de fantaisie, il se trouve être assez rapide, mais ce n'est pas le seul du genre. D'autres appareils tels que les disques durs sont essentiellement la même chose, l'espace plat adressable par un index, mais beaucoup plus lent.
La raison pour laquelle "un tas" existe est qu'il serait impossible pour chaque application de tenter de gérer seule l'utilisation de la RAM. Il y a longtemps, c'est exactement comme cela que les choses se sont passées, les programmeurs ont planifié à l'avance exactement à quoi chaque emplacement de RAM serait utilisé. Comme le logiciel est devenu plus complexe, quelqu'un l'a dit, ne serait-ce pas bien si je pouvais simplement aller dans une boîte noire et dire "J'ai besoin de 10 octets alors donnez-moi" et ne pas avoir à vous soucier de tous les détails complexes de l'endroit et de la façon dont ces 10 octets proviennent ou comment ils sont récupérés. C'est ce qu'est un tas, n'est pas vraiment plus basique que ça.
Chaque fois qu'un thread est créé, il existe des structures de données (et une pile), qui sont acquises en utilisant la même "opération gimme" que je viens de décrire. Une pile à peu près universellement utilisée car elle s'adapte parfaitement aux cadres de pile d'appels de fonctions et à leur nature LIFO. En théorie, chaque invocation de fonction et variables locales pourraient être allouées sur le tas, mais cela serait tout simplement trop cher, par rapport à quelques instructions d'assemblage nécessaires pour mettre à jour le registre du pointeur de pile (ESP sur x86).
Le stockage local de threads (TLS) est également construit sur le dessus du tas. Lorsqu'un thread est créé, dans le cadre d'un déplacement vers le segment de mémoire pour allouer de la mémoire aux structures de gestion, un espace distinct pour TLS est également alloué à partir du segment de mémoire.
Donc à la fin, tout ce que vous avez vraiment est un allocateur de mémoire générique (c'est-à-dire le tas) et tout le reste est une forme spécialisée en plus de cela. En d'autres termes, si vous êtes prêt à renoncer à un aspect de "Je veux allouer autant (ou aussi peu) que je veux, gardez-le aussi longtemps que je veux et gratuit quand je veux", vous pourriez vous en sortir off allocateur de tas générique pour un autre modèle qui offre de la vitesse mais au prix d'une autre limitation.
Prenez la pile. Il est incroyablement rapide par rapport au tas, mais les deux compromis sont 1) vous ne contrôlez pas quand la mémoire est libérée; au lieu de cela, une fois la fonction terminée, tout ce que vous avez alloué est parti et 2) parce que les piles sont généralement de taille limitée, vous devez faire attention d'allouer de grandes quantités de données directement sur la pile.
Un autre type de «modèle de mémoire» est le Virtual Memory Manager (VMM) offert par à peu près tous les principaux systèmes d'exploitation via des appels système. VMM est très similaire au tas dans le sens où vous pouvez demander n'importe quelle quantité de mémoire et la conserver aussi longtemps que vous le souhaitez. Cependant, la limitation est que vous ne pouvez allouer de la mémoire que par multiples de taille de page (par exemple, 4 Ko), donc l'utilisation directe de VMM entraînerait une surcharge importante dans une application typique qui alloue souvent 8 à 24 octets à la fois. En fait, à peu près chaque implémentation de tas est construite au-dessus de VMM spécifiquement pour permettre une allocation très générique, non spécialisée et en petits blocs. Heap va à VMM chaque fois qu'il a besoin de plus de mémoire, puis distribue de nombreux petits morceaux de cette mémoire à l'application.
Si vous avez une application, qui a besoin d'allouer de gros blocs, vous pouvez envisager d'aller directement à VMM, bien que certains tas aient une instruction if à l'intérieur de malloc () et si la taille du bloc est supérieure à un certain seuil, ils vont simplement à VMM pour vous.
Une autre forme d'allocateurs au lieu d'utiliser directement le tas, serait les pools. Un pool est un allocateur spécialisé où tous les blocs sont de la même taille. Les pools (tout comme la pile et TLS) sont construits sur le tas ou VMM. Les piscines sont utiles dans les endroits où vous allouez beaucoup (des millions) de petits objets éphémères de même taille. Imaginez un service réseau traitant les demandes entrantes. Chaque demande client peut entraîner l'allocation de la même structure à N octets pour traiter cette demande. Le compromis avec l'utilisation des pools est que chaque pool ne gère qu'une seule taille de bloc (mais vous pouvez créer plusieurs pools). L'avantage des pools est que, comme tous les objets sont de la même taille, ils ne nécessitent pas de logique complexe. Au lieu de cela, chaque fois que vous avez besoin d'un nouveau bloc, il vous donne simplement celui qui a été récemment libéré.
Et enfin, souvenez-vous de cette chose sur le disque dur que j'ai mentionnée en haut. Vous pouvez avoir un modèle de mémoire qui se comporte comme un système de fichiers et reproduit la même idée d'entrées de répertoire et de nœuds i pour vous permettre une allocation hiérarchique des blocs de données où chaque bloc de données est adressé avec un chemin. C'est exactement ce que fait tmpfs .
Au-delà des choses que j'ai mentionnées, je suis sûr qu'il existe d'autres modèles plus spécialisés, mais à la fin, car tout est basé sur un espace d'adressage plat (c'est-à-dire jusqu'à ce que certains génies proposent une sorte d'espace non-bizarre-un $$ non plat ), tout revient à cet allocateur générique "gimme" qui est soit VMM soit le tas.