Maison > Java > javaDidacticiel > le corps du texte

Comprendre l'analyse d'échappement JVM en 3 minutes

Libérer: 2023-08-15 16:39:17
avant
1266 Les gens l'ont consulté

En tant que développeur Java qualifié, nous savons tous que pratiquement tous les objets sont créés sur le tas. Cependant, il n'y a toujours pas de mot absolu ici, il fait référence à essentiellement tout.

Hier lors d'une interview, un ami a dit que tous les objets sont créés dans le tas, puis s'est moqué de l'intervieweur.

Commencez notre texte principal, parlons aujourd'hui de l'analyse des évasions.

Escape Analysis (Escape Analysis) est actuellement une technologie d'optimisation relativement avant-gardiste dans la machine virtuelle Java. Il s'agit d'un algorithme d'analyse du flux de données global interfonctionnel qui peut réduire efficacement la charge de synchronisation et la pression d'allocation du tas de mémoire dans les programmes Java. Grâce à l'analyse d'échappement, le compilateur Java Hotspot peut analyser la plage d'utilisation de la référence d'un nouvel objet et décider s'il doit allouer cet objet au tas.

Le principe de base de l'analyse d'échappement est  : analyser la portée dynamique des objets. Lorsqu'un objet est défini dans une méthode, il peut être référencé par des méthodes externes, par exemple en étant transmis à d'autres méthodes en tant que paramètres d'appel. une méthode Escape ; elle peut même être accessible par des threads externes, comme l'affectation à des variables d'instance accessibles dans d'autres threads. C'est ce qu'on appelle l'échappement de thread depuis aucun échappement, l'échappement de méthode vers l'échappement de thread, c'est ce qu'on appelle l'objet de bas. à élevé. Différents degrés d’évasion.

Lorsque l'analyse d'échappement est activée, le compilateur peut optimiser le code comme suit :

  1. Élimination synchrone : si l'analyse d'échappement trouve qu'un objet n'est accessible que par un seul thread, les opérations sur cet objet peuvent être asynchrone.
  2. Allocation sur la pile : Si vous êtes sûr qu'un objet ne s'échappera pas du thread, ce serait une très bonne idée d'allouer de la mémoire à cet objet sur la pile. L'espace mémoire occupé par l'objet peut être libéré. avec le cadre de la pile et détruit.
  3. Remplacement scalaire : si l'analyse d'échappement révèle qu'un objet n'est pas accessible par des méthodes externes et que cet objet peut être démantelé, alors le programme ne peut pas créer cet objet lorsqu'il est réellement exécuté, mais en créer directement plusieurs. Alors cette méthode utilise des variables membres à la place. Après avoir divisé l'objet, les variables membres de l'objet peuvent être allouées, lues et écrites sur la pile.

Dans JVM, vous pouvez spécifier s'il faut activer l'analyse d'échappement via les paramètres suivants :

-XX:+DoEscapeAnalysis : indique l'activation de l'analyse d'échappement (elle est activée par défaut après JDK 1.7). -XX:+DoEscapeAnalysis :表示开启逃逸分析(JDK 1.7之后默认开启)。

-XX:-DoEscapeAnalysis

-XX:-DoEscapeAnalysis : Représente Désactivez l'analyse d'échappement. 🎜

Élimination de la synchronisation

La synchronisation des threads elle-même est un processus relativement long. Si l'analyse d'échappement peut déterminer qu'une variable n'échappera pas au thread et ne sera pas accessible par d'autres threads, alors il n'y aura certainement ni lecture ni écriture. de cette variable, les mesures de synchronisation mises en œuvre sur cette variable peuvent être éliminées en toute sécurité.

Comme le code suivant :

public void method() {
    Object o = new Object();
    synchronized (o) {
        System.out.println(o);
    }
}
Copier après la connexion

verrouille 对象o, mais le cycle de vie de l'objet o est le même que celui de la méthode méthode(), donc il ne sera pas accessible par d'autres threads et les problèmes de sécurité des threads ne se produiront pas. sera bloqué pendant la phase de compilation JIT. Optimisé pour ressembler à ceci :

public void method() {
    Object o = new Object();
    System.out.println(o);
}
Copier après la connexion

C'est également connu sous le nom de Lock Elimination.

Allocation sur la pile

Dans la machine virtuelle Java, l'allocation d'espace mémoire pour les objets créés sur le tas Java est presque du bon sens pour les programmeurs Java. Les objets du tas Java sont partagés et visibles par chaque thread. tant que vous détenez une référence à cet objet, vous pouvez accéder aux données d'objet stockées dans le tas. Le sous-système de récupération de place de la machine virtuelle recyclera les objets qui ne sont plus utilisés dans le tas, mais l'action de recyclage, qu'il s'agisse de marquer et de filtrer les objets recyclables, ou de recycler et d'organiser la mémoire, nécessite beaucoup de ressources. Cependant, il existe un cas particulier. Si l'analyse d'échappement confirme que l'objet ne s'échappera pas du thread, il peut être optimisé pour l'allocation sur la pile. Cela élimine le besoin d’allouer de la mémoire sur le tas et élimine le besoin de garbage collection.

Comme le code suivant :

public static void main(String[] args) throws InterruptedException {

    for (int i = 0; i < 1000000; i++) {
        alloc();
    }

    Thread.sleep(100000);
}

private static void alloc() {
    User user = new User();
}
Copier après la connexion

Le code est très simple, il s'agit de créer une boucle 1 million de fois et d'utiliser la méthode alloc() pour créer 1 million d'objets User. L'objet User défini ici dans la méthode alloc() n'est pas référencé par d'autres méthodes, il répond donc aux exigences d'allocation sur la pile.

Les paramètres JVM sont les suivants :

-Xmx2G -Xms2G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
Copier après la connexion

Démarrez le programme et vérifiez le nombre d'instances via l'outil jmap :

jmap -histo pid

num     #instances         #bytes  class name
----------------------------------------------
1:          3771        2198552  [B
2:         10617        1722664  [C
3:        104057        1664912  com.miracle.current.lock.StackAllocationTest$User
Copier après la connexion

Nous pouvons voir que le programme a créé un total de 104057 objets utilisateur, soit bien moins de 1 million. Nous pouvons désactiver l'analyse d'échappement et y jeter un œil à nouveau :

-Xmx2G -Xms2G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
Copier après la connexion

Démarrez le programme et vérifiez le nombre d'instances via l'outil jmap :

jmap -histo 42928

 num     #instances         #bytes  class name
----------------------------------------------
   1:           628       22299176  [I
   2:       1000000       16000000  com.miracle.current.lock.StackAllocationTest$User
Copier après la connexion

Vous pouvez voir qu'un total de 1 million d'objets utilisateur ont été créés après avoir désactivé l'analyse d'échappement. . En comparaison, l'allocation sur la pile joue un rôle important dans la consommation de mémoire du tas et dans le GC.

Remplacement scalaire

Si une donnée ne peut plus être décomposée en données plus petites à représenter, les types de données d'origine dans la machine virtuelle Java (int, long et autres types numériques et types de référence, etc.) ne peuvent pas disparaître En outre décomposées, ces données peuvent alors être appelées scalaires. En revanche, si une donnée peut continuer à être décomposée, elle est appelée un agrégat. Les objets en Java sont des agrégats typiques.

Si l'analyse d'échappement peut prouver qu'un objet ne sera pas accessible en dehors de la méthode et que cet objet peut être démantelé, alors le programme ne peut pas créer cet objet lorsqu'il est réellement exécuté, mais en créer directement plusieurs pour être utilisés par cette méthode.

a le code suivant :

public static void main(String[] args) {

    method();
}

private static void method() {
    User user = new User(25);

    System.out.println(user.age);
}

private static class User {

    private int age;

    public User(int age) {
        this.age = age;
    }
}
Copier après la connexion

method()方法中创建User对象,指定age为25,这里User不会被其他方法引用,也就是说它不会逃逸出方法,并且User是可以拆解为标量的。所以alloc()代码会优化为如下:

private static void alloc() {
    int age = 25;

    System.out.println(age);
}
Copier après la connexion

总结

尽管目前逃逸分析技术仍在发展之中,未完全成熟,但它是即时编译器优化技术的一个重要前进方向,在日后的Java虚拟机中,逃逸分析技术肯定会支撑起一系列更实用、有效的优化技术。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
jvm
source:Java后端技术全栈
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal