Si je comprends bien, en Java, la mémoire de pile contient les primitives et les invocations de méthodes, tandis que la mémoire de tas est utilisée pour stocker des objets.
Supposons que j'ai une classe
class A {
int a ;
String b;
//getters and setters
}
Où la primitive
a
en classeA
sera-t-elle stockée?Pourquoi la mémoire de tas existe-t-elle? Pourquoi ne pouvons-nous pas tout stocker sur la pile?
Lorsque l'objet est nettoyé, la pile associée à l'objet faisant l'objet de la destruction est-elle détruite?
Réponses:
La différence fondamentale entre pile et tas est le cycle de vie des valeurs.
Les valeurs de pile n'existent que dans l'étendue de la fonction dans laquelle elles ont été créées. Une fois renvoyées, elles sont supprimées.
Les valeurs de tas existent cependant sur le tas. Ils sont créés à un moment donné et détruits à un autre (soit par GC, soit manuellement, en fonction de la langue / du temps d'exécution).
Maintenant, Java ne stocke que les primitives sur la pile. Cela réduit la taille de la pile et contribue à la taille réduite des trames de pile individuelles, permettant ainsi davantage d'appels imbriqués.
Les objets sont créés sur le tas et seules les références (qui sont à leur tour des primitives) sont transmises sur la pile.
Ainsi, si vous créez un objet, il est placé sur le tas, avec toutes les variables qui lui appartiennent, afin qu'il puisse persister après le retour de l'appel de la fonction.
la source
char
s sont des nombres et peuvent être utilisés indifféremment. Les références ne sont également que des chiffres faisant référence à une adresse mémoire, longue de 32 ou 64 bits (bien qu'elles ne puissent pas être utilisées telles quelles - à moins que vous ne jouiez avecsun.misc.Unsafe
).boolean
,byte
,short
,char
,int
,long
,float
Etdouble
.)Où sont stockés les champs primitifs?
Les champs primitifs sont stockés en tant que partie de l'objet instancié quelque part . La meilleure façon de voir où cela se trouve est le tas. Cependant , ce n'est pas toujours le cas. Comme décrit dans la théorie et la pratique Java: Légendes de la performance urbaine, revisitées :
Ainsi, au-delà de dire "l'objet est créé et le champ y est aussi", on ne peut pas dire si quelque chose se trouve sur le tas ou sur la pile. Notez que pour les petits objets de courte durée, il est possible que "l'objet" n'existe pas en mémoire en tant que tel et que ses champs soient placés directement dans des registres.
Le papier se termine par:
Donc, si vous avez un code qui ressemble à:
où le
...
ne permet pasqux
de quitter cette portée,qux
peut être alloué sur la pile à la place. C’est en fait une victoire pour la machine virtuelle, car cela signifie qu’elle n’a pas besoin d’être ramassée à la poubelle - elle disparaîtra quand elle quittera la portée.Plus d'informations sur l' analyse d'évasion sur Wikipedia. Pour ceux qui souhaitent approfondir leurs connaissances, Escape Analysis for Java d’IBM. Pour ceux qui viennent d'un monde C #, vous pouvez trouver de bonnes lectures: La pile est un détail d'implémentation et La vérité sur les types de valeur par Eric Lippert (utiles pour les types Java, de nombreux concepts et aspects étant identiques ou similaires) . Pourquoi les livres .Net parlent-ils d'allocation de mémoire pile / pile? va aussi dans cela.
Sur les pourquoi de la pile et du tas
Sur le tas
Alors, pourquoi avoir la pile ou le tas du tout? Pour les choses qui laissent de la place, la pile peut être chère. Considérons le code:
Les paramètres font également partie de la pile. Dans le cas où vous n'avez pas de tas, vous transmettez l'ensemble des valeurs de la pile. C'est bien pour de
"foo"
petites chaînes ... mais que se passerait-il si quelqu'un mettait un fichier XML énorme dans cette chaîne? Chaque appel copierait toute la chaîne sur la pile, ce qui serait une perte de temps.Au lieu de cela, il est préférable de placer les objets qui ont une vie en dehors de la portée immédiate (passés à une autre portée, coincés dans une structure que quelqu'un d'autre maintient, etc.) dans un autre domaine appelé le tas.
Sur la pile
Vous n'avez pas besoin de la pile. On pourrait, hypothétiquement, écrire un langage qui n’utilise pas de pile (de profondeur arbitraire). Un vieux BASIC que j’ai appris dans ma jeunesse l’a fait, on ne pouvait faire que 8 niveaux d’
gosub
appels et toutes les variables étaient globales - il n’y avait pas de pile.L'avantage de la pile est que, lorsque vous avez une variable qui existe avec une étendue, lorsque vous quittez cette étendue, ce cadre de pile est éclaté. Cela simplifie vraiment ce qui existe et ce qui ne l’est pas. Le programme passe à une autre procédure, un nouveau cadre de pile; le programme revient à la procédure et vous revenez à celui qui voit votre étendue actuelle; le programme quitte la procédure et tous les éléments de la pile sont désalloués.
Cela rend vraiment la vie facile pour la personne qui écrit le runtime pour que le code utilise une pile et un tas. Ils consistent simplement en de nombreux concepts et façons de travailler sur le code, ce qui permet à la personne qui l’écrit dans le langage d’être libérée d’y penser explicitement.
La nature de la pile signifie également qu'elle ne peut pas être fragmentée. La fragmentation de la mémoire est un réel problème avec le tas. Vous allouez quelques objets, puis ramassez un objet central, puis vous essayez de trouver de la place pour le prochain objet de grande taille à allouer. C'est le bordel. Pouvoir mettre les choses sur la pile signifie plutôt que vous n'avez pas à vous en occuper.
Quand quelque chose est ramassé
Quand quelque chose est ramassé, il est parti. Mais ce n'est que des ordures collectées car elles ont déjà été oubliées - il n'y a plus de références à l'objet dans le programme auxquelles on peut accéder à partir de l'état actuel du programme.
Je ferai remarquer qu'il s'agit d'une très grande simplification de la collecte des ordures. Il existe de nombreux éboueurs (même en Java - vous pouvez modifier ce dernier en utilisant divers indicateurs ( docs ). Ceux-ci se comportent différemment et les nuances de la façon dont chacune fait les choses sont un peu trop profondes pour cette réponse. Vous voudrez peut-être lire Java Garbage Collection Basics pour avoir une meilleure idée de comment cela fonctionne.
Cela dit, si quelque chose est alloué sur la pile, ce ne sont pas des ordures collectées dans le cadre de
System.gc()
, mais elles sont désallouées lorsque le cadre de la pile apparaît. Si quelque chose se trouve sur le tas et est référencé à partir de quelque chose sur la pile, ce ne sera pas une ordure collectée à ce moment-là.Pourquoi est-ce important?
Pour la plupart, sa tradition. Les manuels écrits, les classes de compilateur et la documentation sur divers bits font l’objet d’une grande importance pour le tas et la pile.
Cependant, les machines virtuelles d’aujourd’hui (JVM et similaires) ont tout mis en oeuvre pour tenter de cacher cela au programmeur. À moins que vous ne manquiez de l'un ou de l'autre et que vous ayez besoin de savoir pourquoi (plutôt que d'augmenter simplement l'espace de stockage de manière appropriée), peu importe.
L'objet est quelque part et il se trouve à l'endroit où il peut être consulté correctement et rapidement pendant la période de temps qu'il existe. Si c'est sur la pile ou le tas - ce n'est pas grave.
la source
la source
Sur le tas, à moins que Java n'alloue l'instance de classe sur la pile en tant qu'optimisation après avoir prouvé via une analyse d'échappement que cela n'affectera pas la sémantique. Il s’agit là d’un détail de la mise en œuvre. Par conséquent, à toutes fins pratiques, à l’exception de la micro-optimisation, la réponse est "sur le tas".
La mémoire de pile doit être allouée et désallouée en dernier dans le premier sorti. La mémoire de tas peut être allouée et désallouée dans n'importe quel ordre.
Lorsque l'objet est collecté, il n'y a plus de références pointant vers lui depuis la pile. S'il y en avait, ils garderaient l'objet en vie. Les primitives de pile ne sont pas du tout collectées car elles sont automatiquement détruites au retour de la fonction.
la source
La mémoire de pile est utilisée pour stocker les variables locales et l'appel de fonction.
Alors que la mémoire de tas est utilisée pour stocker des objets en Java. Peu importe, où l'objet est créé dans le code.
Dans ce cas, la primitive a est associée à un objet de classe A. Donc, il crée dans la mémoire de tas.
Garbage Collector fonctionne dans le cadre de la mémoire Heap, il détruit donc les objets qui ne possèdent pas de chaîne de référence de la racine.
la source
Pour une meilleure compréhension (mémoire Heap / Stack):
la source