Gestion de la mémoire dans Java
⚡ Résumé intelligent
Gestion de la mémoire dans Java explique comment la JVM répartit la mémoire d'exécution entre la pile, le tas et Code, et les régions statiques, la manière dont les références d'objets circulent lors des appels de méthode, et comment le ramasse-miettes récupère les objets inaccessibles afin que les applications restent stables et exemptes de fuites de mémoire.

Qu'est-ce que la mémoire de pile ? Java?
Mémoire de pile dans Java La pile est la zone de la mémoire JVM qui stocke les cadres d'exécution des méthodes, les variables locales et les variables de référence pour chaque thread. L'accès à la pile se fait toujours selon l'ordre LIFO (dernier entré, premier sorti) ; ainsi, la méthode la plus récemment appelée se trouve au sommet de la pile, et ses variables locales sont empilées et dépilées avec le cadre d'exécution.
Chaque fil dans le Java La machine virtuelle dispose de sa propre pile, ce qui garantit l'isolation des appels de méthodes et la sécurité des threads par conception. Les variables locales primitives telles que `int`, `boolean` et `double` résident directement dans le cadre, tandis que les références d'objets stockées dans la pile pointent vers des objets alloués sur le tas.
Qu'est-ce que la mémoire de tas ? Java?
La mémoire du tas est la région partagée de la JVM qui contient toutes les données. Java Les objets et tableaux créés avec l'opérateur `new`, ainsi que toutes les variables de référence qui leur sont associées en tant que champs d'instance, sont stockés dans le tas. Contrairement à la pile, le tas est partagé entre tous les threads, ce qui explique pourquoi l'accès aux objets nécessite souvent une synchronisation.
Le tas est la zone gérée par le ramasse-miettes. Les JVM HotSpot modernes divisent le tas en une génération jeune pour les objets éphémères et une génération ancienne pour les objets persistants, les métadonnées de classe étant stockées dans une région native distincte appelée Metaspace.
Allocation de mémoire dans Java
Allocation de mémoire dans Java Le tas est le processus par lequel la JVM réserve des zones de mémoire virtuelle pour les variables, les instances de classes et de structures lors de l'exécution d'un programme. La mémoire n'est pas allouée à un objet lors de sa déclaration ; seule une référence est créée. L'allocation proprement dite de l'objet a lieu via l'opérateur `new`, de sorte que chaque objet réside sur le tas.
Le Java L'allocation de mémoire est divisée en sections comme suit :
- Heap
- Stack
- Code
- Statique
Cette division de la mémoire est nécessaire pour une gestion efficace de l'environnement d'exécution.
- Le Code Cette section contient votre compilation bytecode.
- Le Stack magasins de la section méthodes, variables locales et variables de référence.
- Le Heap la section contient objets et peuvent également contenir des variables de référence stockées en tant que champs d'instance.
- Le Statique la section contient données statiques et méthodes statiques partagé entre toutes les instances.
Différence entre la variable locale et la variable d'instance
Comprendre où chaque type de variable se situe dans la JVM permet d'expliquer le comportement de la pile et du tas. variable d'instance est déclaré à l'intérieur d'une classe, mais en dehors de toute méthodeet elle réside sur le Tas en tant que partie intégrante de son objet.
class Student{ int num; // num is instance variable public void showData{}
A variable locale est déclaré à l'intérieur d'une méthode, y compris les arguments de la méthode, et réside dans la pile à l'intérieur du cadre actif.
public void sum(int a){ int x = a + 3; // a, x are local variables }
Différence entre pile et tas
La pile et le tas résolvent des problèmes différents au sein de la JVM. La pile offre à chaque thread une allocation rapide et déterministe de données éphémères liées à la portée des méthodes, tandis que le tas fournit une zone partagée pour les objets persistants accessibles à tous les threads. La courte vidéo ci-dessous résume cette différence avant la présentation détaillée qui suit.
Cliquez à nouveau ici si la vidéo n'est pas accessible
Pour voir comment la pile et le tas coopèrent, prenons l'exemple d'une méthode principale qui appelle la méthode m1.
public void m1{ int x = 20; }
Dans la pile JVM, un cadre est créé pour la méthode m1.
La variable x dans m1 est également créée dans le cadre de m1 sur la pile, comme indiqué dans l'image ci-dessous.
La méthode m1 appelle ensuite la méthode m2. Dans la pile, un nouveau cadre est créé pour m2 au-dessus du cadre de m1.
Les variables locales b et c sont également créées à l'intérieur du cadre pour m2 sur la pile.
public void m2(int b){ boolean c; }
Ensuite, m2 appelle la méthode m3. Là encore, un cadre pour m3 est créé au sommet de la pile, comme indiqué ci-dessous.
Supposons maintenant que la méthode m3 crée un objet pour la classe Account, qui possède deux variables d'instance int p et int q.
class Account { int p; int q; }
Voici le code de la méthode m3.
public void m3(){ Account ref = new Account(); // more code }
L'instruction new Account() crée un objet Account sur le tas.
La variable de référence ref est créée sur la pile à l'intérieur du cadre pour m3.
L'opérateur d'affectation fait pointer la variable de référence vers l'objet sur le tas.
Une fois l'exécution de la méthode terminée, le contrôle est renvoyé à la méthode appelante, qui dans ce cas est la méthode m2.
Le cadre de la méthode m3 est vidé de la pile.
Puisque la variable de référence ne pointe plus vers l'objet sur le tas, cet objet devient éligible au ramasse-miettes.
Une fois la méthode m2 terminée, elle est dépilée et toutes ses variables deviennent inaccessibles. Il en va de même pour la méthode m1, et finalement le contrôle est rendu à la méthode principale.
Que se passe-t-il si un objet contient une autre référence comme variable d'instance ?
public static void main(String args[]) { A parent = new A(); // more code } class A { B child = new B(); int e; } class B { int c; int d; }
Dans ce cas, la variable de référence child réside dans le tas en tant que partie de l'objet A, et pointe à son tour vers son propre objet B, comme indiqué ci-dessous.
Qu’est-ce que la collecte des déchets Java?
Collecte des déchets à Java Le ramasse-miettes est le processus par lequel la JVM gère automatiquement la mémoire. Il repère les objets qui ne sont plus accessibles par aucune référence active et libère leur mémoire. L'allocation dynamique de mémoire s'effectue via l'opérateur `new`, et la mémoire reste allouée tant que le programme fait référence à l'objet.
Lorsqu'il ne reste plus aucune référence à un objet, celui-ci est considéré comme inutile et la mémoire qu'il occupait peut être libérée. Il n'est pas nécessaire de détruire explicitement un objet car Java La désallocation est gérée automatiquement par le biais du ramasse-miettes.
La technique sous-jacente est connue sous le nom de Collecte des orduresLes programmes qui ne parviennent pas à libérer de la mémoire finissent par planter lorsqu'il ne reste plus rien à allouer. On dit alors que ces programmes ont… fuites de mémoire. Collecte des déchets à Java s'exécute automatiquement pendant toute la durée du programme, ce qui élimine la charge de la désaffectation manuelle et réduit le risque de fuites.
En C, en revanche, c'est au programmeur qu'il incombe de libérer la mémoire allouée dynamiquement via la fonction free(). C'est là que… Java La gestion de la mémoire offre un avantage considérable.
Les JVM HotSpot modernes intègrent plusieurs collecteurs de déchets optimisés pour différentes charges de travail. Le collecteur de déchets G1 par défaut vise un débit équilibré et des temps de pause sur des tas de plusieurs gigaoctets. ZGC et Shenandoah visent des pauses inférieures à la milliseconde sur des tas très volumineux, ce qui les rend particulièrement performants.tractive pour les services sensibles à la latence. Choisir le bon collecteur et ajuster les tailles de la jeune génération, de l'ancienne génération et du métaspace est une compétence essentielle pour Java travail de performance.
À noter: Tous les objets sont créés dans la zone de mémoire appelée Heap, qui est la région gérée par le ramasse-miettes.
Exemple : Pour apprendre le mécanisme du collecteur de déchets dans Java
Ce guide explique à quel moment les références deviennent éligibles au nettoyage de la mémoire (Garbage Collection) dans un programme simple.
Étape 1) Copiez le code suivant dans un éditeur.
class Student{ int a; int b; public void setData(int c,int d){ a=c; b=d; } public void showData(){ System.out.println("Value of a = "+a); System.out.println("Value of b = "+b); } public static void main(String args[]){ Student s1 = new Student(); Student s2 = new Student(); s1.setData(1,2); s2.setData(3,4); s1.showData(); s2.showData(); //Student s3; //s3=s2; //s3.showData(); //s2=null; //s3.showData(); //s3=null; //s3.showData(); } }
Étape 2) Enregistrez, compilez et exécutez le code. Comme indiqué dans le diagramme, deux objets et deux variables de référence sont créés.
Étape 3) Décommentez les lignes 20, 21 et 22. Enregistrez, compilez et exécutez le code.
Étape 4) Comme le montre le diagramme ci-dessous, deux variables de référence pointent désormais vers le même objet.
Étape 5) Décommentez les lignes 23 et 24. Enregistrez, compilez et exécutez le code.
Étape 6) Comme indiqué ci-dessous, s2 devient nul, mais s3 pointe toujours vers l'objet, donc l'objet n'est pas encore éligible pour le ramasse-miettes.
Étape 7) Décommentez les lignes 25 et 26. Enregistrez, compilez et exécutez le code.
Étape 8) À ce stade, aucune référence ne pointe vers l'objet, qui devient donc éligible au ramasse-miettes. Le ramasse-miettes le supprime de la mémoire, et il est impossible de le récupérer.
Comment supprimer un objet dans Java?
Java ne propose pas d'opérateur de suppression manuelle, l'approche standard consiste donc à supprimer toute référence à l'objet afin que le ramasse-miettes puisse le récupérer.
1) Pour qu'un objet soit éligible au ramasse-miettes, assignez la valeur null à toutes les variables de référence qui pointent vers lui.
2) Les types primitifs ne sont pas des objets et ne peuvent donc pas être affectés à la valeur null. Leur espace mémoire est automatiquement libéré lorsque le cadre de pile englobant est dépilé.


















