Mémoire de pile et espace de tas en Java

1. Introduction

Pour exécuter une application de manière optimale, JVM divise la mémoire en mémoire de pile et mémoire de tas. Chaque fois que nous déclarons de nouvelles variables et objets, appelons une nouvelle méthode, déclarons une chaîne ou effectuons des opérations similaires, JVM désigne la mémoire pour ces opérations à partir de la mémoire de pile ou de l'espace de tas.

Dans ce didacticiel, nous aborderons ces modèles de mémoire. Nous énumérerons quelques différences clés entre eux, comment ils sont stockés dans la RAM, les fonctionnalités qu'ils offrent et où les utiliser.

2. Mémoire de pile en Java

La mémoire de pile en Java est utilisée pour l'allocation de mémoire statique et l'exécution d'un thread. Il contient des valeurs primitives spécifiques à une méthode et des références à des objets qui se trouvent dans un tas, référencés à partir de la méthode.

L'accès à cette mémoire est dans l'ordre Last-In-First-Out (LIFO). Chaque fois qu'une nouvelle méthode est appelée, un nouveau bloc au-dessus de la pile est créé qui contient des valeurs spécifiques à cette méthode, comme des variables primitives et des références à des objets.

Lorsque la méthode termine son exécution, le cadre de pile correspondant est vidé, le flux revient à la méthode appelante et de l'espace devient disponible pour la méthode suivante.

2.1. Principales caractéristiques de la mémoire de pile

Outre ce que nous avons discuté jusqu'à présent, voici quelques autres fonctionnalités de la mémoire de pile:

  • Il grandit et rétrécit au fur et à mesure que de nouvelles méthodes sont appelées et renvoyées respectivement
  • Les variables à l'intérieur de la pile n'existent que tant que la méthode qui les a créées est en cours d'exécution
  • Il est automatiquement alloué et désalloué lorsque la méthode termine l'exécution
  • Si cette mémoire est pleine, Java lance java.lang.StackOverFlowError
  • L'accès à cette mémoire est rapide par rapport à la mémoire de tas
  • Cette mémoire est threadsafe car chaque thread fonctionne dans sa propre pile

3. Heap Space à Java

L'espace de tas en Java est utilisé pour l'allocation dynamique de mémoire pour les objets Java et les classes JRE au moment de l'exécution . Les nouveaux objets sont toujours créés dans l'espace du tas et les références à ces objets sont stockées dans la mémoire de la pile.

Ces objets ont un accès global et sont accessibles de n'importe où dans l'application.

Ce modèle de mémoire est divisé en parties plus petites appelées générations, ce sont:

  1. Jeune génération - c'est là que tous les nouveaux objets sont attribués et vieillis. Un garbage collection mineur se produit lorsque cela se remplit
  2. Ancienne génération ou génération permanente - c'est là que sont stockés les objets qui ont survécu longtemps. Lorsque des objets sont stockés dans la jeune génération, un seuil pour l'âge de l'objet est défini et lorsque ce seuil est atteint, l'objet est déplacé vers l'ancienne génération.
  3. Génération permanente - il s'agit de métadonnées JVM pour les classes d'exécution et les méthodes d'application

Ces différentes parties sont également traitées dans cet article - Différence entre JVM, JRE et JDK.

Nous pouvons toujours manipuler la taille de la mémoire du tas selon nos besoins. Pour plus d'informations, visitez cet article lié à Baeldung.

3.1. Principales caractéristiques de la mémoire Java Heap

Outre ce dont nous avons discuté jusqu'à présent, voici quelques autres caractéristiques de l'espace de tas:

  • Il est accessible via des techniques complexes de gestion de la mémoire qui incluent la jeune génération, l'ancienne ou la génération permanente et la génération permanente
  • Si l'espace du tas est plein, Java renvoie java.lang.OutOfMemoryError
  • L'accès à cette mémoire est relativement plus lent que la mémoire de pile
  • Cette mémoire, contrairement à stack, n'est pas automatiquement désallouée. Il a besoin de Garbage Collector pour libérer les objets inutilisés afin de conserver l'efficacité de l'utilisation de la mémoire
  • Contrairement à la pile, un tas n'est pas threadsafe et doit être protégé en synchronisant correctement le code

4. Exemple

Sur la base de ce que nous avons appris jusqu'à présent, analysons un code Java simple et évaluons comment la mémoire est gérée ici:

class Person { int id; String name; public Person(int id, String name) { this.id = id; this.name = name; } } public class PersonBuilder { private static Person buildPerson(int id, String name) { return new Person(id, name); } public static void main(String[] args) { int id = 23; String name = "John"; Person person = null; person = buildPerson(id, name); } }

Analysons cette étape par étape:

  1. En entrant dans la méthode main () , un espace dans la mémoire de la pile serait créé pour stocker les primitives et les références de cette méthode
    • La valeur primitive de l' identifiant entier sera stockée directement dans la mémoire de la pile
    • La variable de référence personne de type Person sera également créée dans la mémoire de la pile qui pointera vers l'objet réel dans le tas
  2. L'appel au constructeur paramétré Person (int, String) depuis main () allouera plus de mémoire au-dessus de la pile précédente. Cela stockera:
    • La référence d'objet this de l'objet appelant dans la mémoire de pile
    • La valeur primitive id dans la mémoire de la pile
    • La variable de référence du nom de l' argument String qui pointera vers la chaîne réelle du pool de chaînes dans la mémoire du tas
  3. La méthode principale appelle en outre la méthode statique buildPerson () , pour laquelle une allocation supplémentaire aura lieu dans la mémoire de la pile en plus de la précédente. Cela stockera à nouveau les variables de la manière décrite ci-dessus.
  4. Cependant, pour l'objet person nouvellement créé de type Person , toutes les variables d'instance seront stockées dans la mémoire du tas.

Cette allocation est expliquée dans ce schéma:

5. Résumé

Avant de conclure cet article, résumons rapidement les différences entre la mémoire de pile et l'espace de tas:

Paramètre Mémoire de pile Espace de tas
Application La pile est utilisée par parties, une à la fois lors de l'exécution d'un thread L'application entière utilise l'espace du tas pendant l'exécution
Taille La pile a des limites de taille en fonction du système d'exploitation et est généralement plus petite que le tas Il n'y a pas de limite de taille sur le tas
Espace de rangement Stocke uniquement les variables primitives et les références aux objets créés dans Heap Space Tous les objets nouvellement créés sont stockés ici
Ordre Il est accessible à l'aide du système d'allocation de mémoire Last-in First-out (LIFO) Cette mémoire est accessible via des techniques complexes de gestion de la mémoire qui incluent la jeune génération, l'ancienne ou la génération permanente et la génération permanente.
La vie La mémoire de pile n'existe que tant que la méthode actuelle est en cours d'exécution L'espace de tas existe tant que l'application s'exécute
Efficacité Comparativement beaucoup plus rapide à allouer par rapport au tas Plus lent à allouer par rapport à la pile
Allocation / Désallocation Cette mémoire est automatiquement allouée et désallouée lorsqu'une méthode est appelée et renvoyée respectivement L'espace de tas est alloué lorsque de nouveaux objets sont créés et désalloués par Gargabe Collector lorsqu'ils ne sont plus référencés

6. Conclusion

La pile et le tas sont deux façons dont Java alloue la mémoire. Dans cet article, nous avons compris comment ils fonctionnent et quand les utiliser pour développer de meilleurs programmes Java.

Pour en savoir plus sur la gestion de la mémoire en Java, consultez cet article ici. Nous avons également abordé le JVM Garbage Collector qui est brièvement abordé dans cet article.