Zone de tas de données d'exécution JVM (mémoire de tas)

Zone de tas de données d'exécution

Le concept de base du tas

La description du tas Java dans la "Spécification de la machine virtuelle Java" est la suivante: toutes les instances d'objet et tous les tableaux doivent être alloués sur le tas au moment de l'exécution. (Le tas est la zone de données d'exécution à partir de laquelle la mémoire de toutes les instances de classe et tableaux est allouée).

Mais d'un point de vue pratique, «presque» toutes les instances d'objets allouent de la mémoire ici. Étant donné que certains objets sont encore alloués sur la pile et que les tableaux et les objets peuvent ne jamais être stockés sur la pile, car le cadre de pile enregistre une référence, cette référence pointe vers l'emplacement de l'objet ou du tableau dans le tas.

  • Le tas est unique à un processus JVM, c'est-à-dire qu'un processus correspond à une instance JVM, mais le processus contient plusieurs threads, et ils partagent le même espace de tas;
  • Il n'existe qu'un seul segment de mémoire pour une instance JVM et le segment de mémoire est la zone centrale de la gestion de la mémoire Java;
  • La zone de tas Java est créée au démarrage de la JVM et sa taille est déterminée, et il s'agit du plus grand espace mémoire géré par la JVM;
  • Mais la taille de la mémoire du tas peut être ajustée;
  • La "Spécification de la machine virtuelle Java" stipule que le tas peut être dans un espace mémoire physiquement discontinu, mais logiquement, il doit être considéré comme continu (comparable à un système d'exploitation);
  • Le tas Java peut être divisé en tampons privés de threads (Thread Local Allocation Buffer, TLAB), ce qui signifie que toutes les informations du tas ne sont pas partagées par les threads.

Le code suivant explique la mémoire du tas:

public class HeapDemo {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("start...");
        try {
    
    
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        System.out.println("end...");
    }
}

Définissez la taille du tas:

-Xms10m: mémoire de tas minimum
-Xmx10m: mémoire de tas maximum
Insérez la description de l'image ici

La figure suivante montre l'utilisation de Java VisualVM pour afficher le contenu de l'espace de tas via le plug-in GC dans VisualVM.
Insérez la description de l'image ici

Une fois la méthode terminée, les objets du tas ne seront pas supprimés immédiatement, ils ne seront supprimés que pendant le garbage collection, c'est-à-dire que lorsque le GC est déclenché, ils seront collectés.

Parce que si les objets du tas sont récupérés immédiatement, le thread utilisateur sera affecté.

La connexion entre le tas, la pile Java et la zone de méthode:
Insérez la description de l'image ici
répartition de la mémoire du tas

La mémoire du tas de Java 7 et avant est logiquement divisée en trois parties: zone nouveau-né + zone de soins senior + zone permanente:

  • Young Generation Space Young / New est divisé en zone Eden et zone Survivor;
  • Espace de génération de tenure Old / Tenure;
  • Espace permanent Perm.

La mémoire du tas de Java 8 et des versions ultérieures est logiquement divisée en trois parties: Zone de pension de la zone du nouveau-né + méta-espace:

  • Young / New in Young Generation Space est divisé en zone Eden et zone Survivor;
  • Espace de génération de tenure Old / Tenure;
  • Meta Space Meta.

Convention: Zone nouveau-né -> Nouvelle génération -> Jeune génération, zone de soins seniors -> Zone plus âgée -> Ancienne génération, zone permanente -> Génération permanente La
Insérez la description de l'image ici
structure interne de l' espace du tas, avant JDK1.8, remplace la génération permanente au méta-espace! ! !
Insérez la description de l'image ici
L'espace de tas comprend logiquement le Cénozoïque, l'Ancienne Génération et le Metaspace, mais ne comprend en réalité que le Cénozoïque et l'Ancienne Génération. ! !

Définir la taille de la mémoire du tas et le MOO

La zone de tas Java est utilisée pour stocker les instances d'objet Java, de sorte que la taille du tas est déjà définie au démarrage de la JVM et peut être définie par les options "-Xmx" et "-Xms".

  • "-Xms" est utilisé pour indiquer la mémoire initiale de la zone de tas, ce qui équivaut à -xx: InitialHeapSize;
  • "-Xmx" est utilisé pour indiquer la mémoire maximale de la zone de tas, ce qui équivaut à -XX: MaxHeapSize.
  • Une fois que la taille de la mémoire dans la zone de tas dépasse la mémoire maximale spécifiée par "-xmx", une exception outofMemoryError sera levée.
  • Habituellement, les deux paramètres -Xms et -Xmx sont configurés avec la même valeur. Le but est de pouvoir calculer la taille de la zone de tas sans recalculer la zone de tas une fois que le mécanisme de récupération de mémoire Java a nettoyé la zone de tas, améliorant ainsi les performances.

par défaut:

  1. Taille de la mémoire initiale: taille de la mémoire de l'ordinateur physique / 64;
  2. Taille maximale de la mémoire: taille de la mémoire physique de l'ordinateur / 4.

Le test de code suivant pour afficher la taille de la mémoire du tas:

public class HeapSpaceInitial {
    
    
    public static void main(String[] args) {
    
    

        //返回Java虚拟机中的堆内存总量
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        //返回Java虚拟机试图使用的最大堆内存量
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;

        System.out.println("-Xms : " + initialMemory + "M");
        System.out.println("-Xmx : " + maxMemory + "M");

        //System.out.println("系统内存大小为:" + initialMemory * 64.0 / 1024 + "G");
        //System.out.println("系统内存大小为:" + maxMemory * 4.0 / 1024 + "G");

        try {
    
    
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }
}

Résultat de sortie

-Xms : 246M
-Xmx : 3934M

Comment afficher l'allocation de mémoire de la mémoire du tas:

jps  ->  jstat -gc 进程id

Insérez la description de l'image ici
Insérez la description de l'image ici
Exemple de OutOfMemory

Exemple de code:

public class OOMTest {
    
    
    public static void main(String[] args) {
    
    
        ArrayList<Picture> list = new ArrayList<>();
        while(true){
    
    
            try {
    
    
                Thread.sleep(20);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            list.add(new Picture(new Random().nextInt(1024 * 1024)));
        }
    }
}

class Picture{
    
    
    private byte[] pixels;

    public Picture(int length) {
    
    
        this.pixels = new byte[length];
    }
}

Définir les paramètres de démarrage

-Xms500m -Xmx:500m
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.heu.heap.OOMTest.main(OOMTest.java:21)

Affichez l'utilisation de la mémoire spécifique via l'outil VisualVM:

Insérez la description de l'image ici
On peut voir que lorsque le tas utilisé atteint 500, une exception MOO se produit.

Jeunes et vieux

Les objets Java stockés dans la JVM peuvent être divisés en deux catégories:

  • Un type est des objets instantanés avec un cycle de vie court. Ce type d'objet est créé et meurt très rapidement. Si le cycle de vie est court, il peut être recyclé dans le temps;
  • Le cycle de vie d'un autre type d'objet est très long et, dans certains cas extrêmes, peut encore être cohérent avec le cycle de vie de la JVM.

Si la zone de tas Java est encore subdivisée, elle peut être divisée en jeune génération (YoungGen) et ancienne génération (oldGen).

Parmi eux, la jeune génération peut être divisée en espace Eden, espace Survivor0 et espace Survivor1 (parfois appelé d'une zone à l'autre).
Insérez la description de l'image ici
Les paramètres de tas suivants ne sont généralement pas ajustés pendant le développement:
Insérez la description de l'image ici

  • Eden : De : à -> 8: 1: 1
  • La nouvelle génération: l'ancienne génération -> 1: 2

Configurez la proportion de la jeune génération et de l'ancienne génération dans la structure du tas:

  • La valeur par défaut -XX: NewRatio = 2 signifie que la nouvelle génération compte pour 1, l'ancienne génération pour 2 et la nouvelle génération pour 1/3 du tas entier;
  • Vous pouvez modifier -XX: NewRatio = 4, ce qui signifie que la nouvelle génération occupe 1, l'ancienne génération en occupe 4 et la nouvelle génération occupe 1/5 du tas entier;
  • Lorsqu'il est constaté qu'il y a trop d'objets avec un long cycle de vie dans l'ensemble du projet, alors vous pouvez ajuster la taille de l'ancienne génération pour le réglage;
  • Dans la machine virtuelle HotSpot, le ratio par défaut de l'espace Eden et des deux autres espaces survivants est de 8: 1: 1. Bien entendu, les développeurs peuvent ajuster ce ratio d'espace via l'option "-xx: SurvivorRatio". Par exemple -xx: SurvivorRatio = 8.

Presque tous les objets Java sont nouveaux dans la zone Eden, et la plupart (80%) des objets Java sont détruits dans la nouvelle génération (certains grands objets iront directement à l'ancienne génération lorsqu'ils ne peuvent pas être stockés dans la zone Eden).

Vous pouvez utiliser l'option "-Xmn" pour définir la taille maximale de la mémoire de la nouvelle génération.
Et ce paramètre utilise généralement la valeur par défaut.
Insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/qq_33626996/article/details/113888562
conseillé
Classement