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 :
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. 🎜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); } }
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); }
C'est également connu sous le nom de Lock Elimination.
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(); }
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
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
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
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
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.
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; } }
在method()
方法中创建User对象,指定age为25,这里User不会被其他方法引用,也就是说它不会逃逸出方法,并且User是可以拆解为标量的。所以alloc()
代码会优化为如下:
private static void alloc() { int age = 25; System.out.println(age); }
尽管目前逃逸分析技术仍在发展之中,未完全成熟,但它是即时编译器优化技术的一个重要前进方向,在日后的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!