Il semble que chaque livre .net parle des types de valeur par rapport aux types de référence et en fait un point vers (souvent de manière incorrecte) l’état où chaque type est stocké - le tas ou la pile. Habituellement, cela fait partie des premiers chapitres et est présenté comme un fait très important. Je pense que c'est même couvert lors des examens de certification . Pourquoi la pile contre le tas est-elle aussi importante pour les développeurs (débutants) .Net? Vous allouez des choses et ça marche, non?
36
Réponses:
Je suis convaincu que la tradition est la principale raison pour laquelle cette information est considérée comme importante . Dans les environnements non gérés, la distinction entre pile et tas est importante et nous devons allouer et supprimer manuellement la mémoire que nous utilisons. Maintenant, la récupération de place prend en charge la gestion, donc ils ignorent ce bit. Je ne pense pas que le message soit vraiment passé: nous ne devons pas nous soucier du type de mémoire utilisé.
Comme Fede l'a souligné, Eric Lippert a des choses très intéressantes à dire à ce sujet: http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx .
À la lumière de cette information, vous pouvez ajuster mon premier paragraphe comme suit: "La raison pour laquelle les gens incluent cette information et supposent que c'est important, c'est en raison d'informations inexactes ou incomplètes associées à la nécessité de posséder cette connaissance dans le passé."
Pour ceux qui pensent que c'est toujours important pour des raisons de performance: quelles actions prendriez-vous pour déplacer quelque chose du tas à la pile si vous mesuriez les choses et découvriez que c'était important? Plus probablement, vous trouveriez un moyen complètement différent d’améliorer les performances pour la zone à problèmes.
la source
Je suis complètement d'accord; Je le vois tout le temps.
Une des raisons est que beaucoup de gens sont venus en C # (ou dans d’autres langages .NET) à partir d’un arrière-plan C ou C ++. Étant donné que ces langues ne vous imposent pas les règles relatives à la durée de stockage, vous devez les connaître et mettre en œuvre votre programme avec soin pour les suivre.
Maintenant, connaître ces règles et les suivre en C ne nécessite pas que vous compreniez "le tas" et "la pile". Mais si vous comprenez comment fonctionnent les structures de données, il est souvent plus facile de comprendre et de suivre les règles.
Lors de la rédaction d'un livre pour débutant, il est naturel qu'un auteur explique les concepts dans le même ordre qu'il les a appris. Ce n'est pas nécessairement l'ordre qui a du sens pour l'utilisateur. J'étais récemment éditeur technique du livre pour débutants C # 4 de Scott Dorman, et l'une des choses que j'ai appréciées à ce sujet est que Scott a choisi un ordre assez judicieux pour les sujets, plutôt que de commencer sur des sujets assez avancés en gestion de la mémoire.
Une autre partie de la raison est que certaines pages de la documentation MSDN mettent fortement l’accent sur les considérations de stockage. Une documentation MSDN particulièrement ancienne, qui traîne toujours depuis le début. Une grande partie de cette documentation contient des erreurs subtiles qui n'ont jamais été supprimées, et vous devez vous rappeler qu'elle a été écrite à un moment donné de l'histoire et pour un public particulier.
À mon avis, ce n'est pas le cas. Ce qui est beaucoup plus important à comprendre, ce sont des choses comme:
Etc.
C'est l'idéal.
Maintenant, il y a des situations dans lesquelles cela compte. La collecte des ordures ménagères est géniale et relativement peu coûteuse, mais elle n’est pas gratuite. Copier de petites structures est relativement peu coûteux, mais n’est pas gratuit. Il existe des scénarios de performances réalistes dans lesquels vous devez équilibrer le coût de la pression de collecte par rapport au coût d'une copie excessive. Dans ces cas, il est très utile de bien comprendre la taille, l'emplacement et la durée de vie réelle de toutes les mémoires pertinentes.
De même, il existe des scénarios d'interopérabilité réalistes dans lesquels il est nécessaire de savoir ce qu'il y a sur la pile et ce qu'il y a sur le tas, et ce que le garbage collector pourrait déplacer. C'est pourquoi C # a des fonctionnalités telles que "fixed", "stackalloc" et ainsi de suite.
Mais ce sont tous des scénarios avancés. Idéalement, un programmeur débutant n'a pas besoin de s'inquiéter de ce genre de choses.
la source
Vous manquez tous le point. La distinction entre pile / tas est importante en raison de sa portée .
Une fois que x sort de la portée, l’objet créé disparaît catégoriquement . C'est uniquement parce qu'il est alloué sur la pile, pas le tas. Il n’ya rien qui aurait pu entrer dans la partie "..." de la méthode qui puisse changer ce fait. En particulier, les assignations ou les appels de méthodes ne peuvent avoir que des copies de la structure S, et non pas créer de nouvelles références pour lui permettre de rester en vie.
Histoire totalement différente! Puisque x est maintenant sur le tas , son objet (c’est-à-dire, l’ objet lui - même , et non une copie de celui-ci) pourrait très bien continuer à vivre après que x soit sorti de sa portée. En fait, la seule façon pour qu'il ne continue pas à vivre est si x en est la seule référence. Si les assignations ou les appels de méthode dans la partie "..." ont créé d'autres références qui sont encore "actives" au moment où x sort de la portée, cet objet continue à exister.
C’est un concept très important et la seule façon de vraiment comprendre «quoi et pourquoi» est de faire la différence entre l’allocation de pile et celle de tas.
la source
...
fichierx
peut être converti en un champ d'une classe générée par le compilateur et donc plus longtemps que l'étendue indiquée. Personnellement, je trouve désagréable l’idée d’un levage implicite, mais les concepteurs de langage semblent aller de l’avant (au lieu d’exiger que toute variable qui est soulevée ait quelque chose dans sa déclaration qui le spécifie). Pour garantir l'exactitude du programme, il est souvent nécessaire de prendre en compte toutes les références pouvant exister à un objet. Il est utile de savoir qu'au moment du retour d'une routine, il ne restera aucune copie d'une référence passée.structType foo
, l'emplacement de stockagefoo
contient le contenu de ses champs; Sifoo
est sur la pile, ses champs le sont aussi. Sifoo
est sur le tas, ses champs le sont aussi. Si sefoo
trouve dans un Apple II en réseau, ses champs le sont également. En revanche, s’ilfoo
s’agissait d’un type de classe, il contiendrait soitnull
une référence à un objet. La seule situation dans laquellefoo
on puisse dire que le type de classe est celui qui contient les champs de l'objet serait s'il s'agissait du seul champ d'une classe et contenait une référence à lui-même.En ce qui concerne POURQUOI couvrent-ils le sujet, je conviens avec @Kirk que c’est un concept important, que vous devez comprendre. Mieux vous connaîtrez les mécanismes, mieux vous pourrez faire de superbes applications performantes.
Maintenant, Eric Lippert semble être d’accord avec vous pour dire que le sujet n’est pas correctement traité par la plupart des auteurs. Je vous recommande de lire son blog pour bien comprendre ce qui se cache sous le capot.
la source
Eh bien, je pensais que c’était l’intérêt des environnements gérés. J'irais même jusqu'à appeler cela un détail d'implémentation du moteur d'exécution sous-jacent sur lequel vous ne devriez PAS faire d'hypothèse, car cela pourrait changer à tout moment.
Je ne connais pas grand chose à propos de .NET, mais autant que je sache, c'est JITted avant son exécution. Le JIT, par exemple, pourrait effectuer une analyse d'évasion et ce qui ne le serait pas et tout à coup, des objets se trouveraient sur la pile ou simplement dans certains registres. Vous ne pouvez pas savoir cela.
Je suppose que certains livres traitent de ce sujet simplement parce que les auteurs lui attribuent une grande importance ou parce qu'ils supposent que leur public le fait (par exemple, si vous écrivez un "C # pour les programmeurs C ++", vous devriez probablement couvrir le sujet).
Néanmoins, je pense qu'il n'y a pas grand chose de plus à dire que "la mémoire est gérée". Sinon, les gens pourraient tirer de mauvaises conclusions.
la source
Vous devez comprendre le fonctionnement de l'allocation de mémoire pour l'utiliser efficacement même si vous n'avez pas à le gérer explicitement. Cela vaut pour presque toutes les abstractions en informatique.
la source
Il peut y avoir des cas extrêmes où cela peut faire la différence. L'espace de pile par défaut est 1 meg alors que le tas est de plusieurs gig. Ainsi, si votre solution contient un grand nombre d’objets, vous pouvez manquer d’espace de pile tout en disposant de beaucoup d’espace.
Cependant, pour la plupart, c'est assez académique.
la source
Comme vous le dites, C # est supposé résumer la gestion de la mémoire, et l’allocation tas-pile est une information de mise en œuvre que le développeur ne devrait en principe pas connaître.
Le problème est que certaines choses sont vraiment difficiles à expliquer de manière intuitive sans se référer à ces détails d'implémentation. Essayez d'expliquer le comportement observable lorsque vous modifiez des types de valeurs mutables - il est presque impossible de le faire sans faire référence à la distinction pile / tas. Ou essayez d’expliquer pourquoi vous avez même des types de valeur dans la langue et quand vous les utiliseriez? Vous devez comprendre la distinction afin de donner un sens à la langue.
Notez que les livres sur Python ou JavaScript ne font pas une grosse affaire s’ils le mentionnent même. En effet, tout est soit alloué, soit immuable, ce qui signifie que les différentes sémantiques de la copie ne sont jamais prises en compte. Dans ces langages, l’abstraction de la mémoire fonctionne; en C #, elle fuit.
la source