Maison  >  Article  >  Java  >  Explication graphique et textuelle détaillée du pool de constantes Java

Explication graphique et textuelle détaillée du pool de constantes Java

尚
avant
2019-11-30 16:36:541982parcourir

Explication graphique et textuelle détaillée du pool de constantes Java

Le pool constant Java est un sujet récurrent et un favori des intervieweurs. Il y a une variété de questions que Xiaocai a déjà entendu parler du pool constant.

Recommandation : Tutoriel vidéo Java

Distribution de la mémoire virtuelle jvm :

Explication graphique et textuelle détaillée du pool de constantes Java

Le compteur du programme est l'endroit où se trouve le jvm exécute le programme. Le pipeline stocke certaines instructions de saut. C'est trop avancé pour que Xiao Cai puisse le comprendre.

La pile de méthodes locales est la pile utilisée par la jvm pour appeler les méthodes du système d'exploitation.

La pile de machine virtuelle est la pile utilisée par jvm pour exécuter du code java.

La zone de méthode stocke certaines constantes, variables statiques, informations de classe, etc., qui peuvent être comprises comme l'emplacement de stockage des fichiers de classe en mémoire.

Le tas de la machine virtuelle est le tas utilisé par la jvm pour exécuter du code java.

Le pool de constantes en Java est en fait divisé en deux formes : le pool de constantes statiques et le pool de constantes d'exécution.

Le pool de constantes dites statiques est le pool de constantes dans le fichier *.class. Le pool de constantes dans le fichier de classe contient non seulement des littéraux de chaîne (nombre), mais contient également des informations de classe et de méthode, occupant absolument. aucune partie du fichier de classe.

Quant au pool de constantes d'exécution, une fois que la machine virtuelle jvm a terminé l'opération de chargement de classe, elle charge le pool de constantes dans le fichier de classe dans la mémoire et l'enregistre dans la zone de méthode. Nous l'appelons souvent la constante. pool , fait référence au pool de constantes d'exécution dans la zone de méthode.

Ensuite, nous citerons quelques exemples de pools constants populaires sur Internet, puis nous les utiliserons pour expliquer.

String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hel" + "lo";
String s4 = "Hel" + new String("lo");
String s5 = new String("Hello");
String s6 = s5.intern();
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;
          
System.out.println(s1 == s2);  // true
System.out.println(s1 == s3);  // true
System.out.println(s1 == s4);  // false
System.out.println(s1 == s9);  // false
System.out.println(s4 == s5);  // false
System.out.println(s1 == s6);  // true

Tout d'abord, en Java, l'opérateur == est utilisé directement pour comparer les adresses de référence de deux chaînes, pas le contenu. Veuillez utiliser String.equals() pour comparer le contenu.

s1 == s2 est très facile à comprendre. Lors de l'attribution de valeurs à s1 et s2, les deux utilisent des chaînes littérales. Pour parler franchement, cela signifie écrire directement la chaîne à mort lors de la compilation. de littéral sera directement placé dans le pool de constantes du fichier de classe pour réaliser la réutilisation. Après avoir chargé le pool de constantes d'exécution, s1 et s2 pointent vers la même adresse mémoire, ils sont donc égaux.

s1 == s3 a un piège. Bien que s3 soit une chaîne épissée dynamiquement, toutes les parties impliquées dans l'épissage sont des littéraux connus. Lors de la compilation, cet épissage sera optimisé, le compilateur l'épellera directement. pour vous, donc String s3 = "Hel" + "lo"; est optimisé en String s3 = "Hello"; dans le fichier de classe, donc s1 == s3 est établi.

Bien sûr, s1 == s4 n'est pas égal. Bien que s4 soit également épissé, la nouvelle partie String("lo") n'est pas un littéral connu et est une partie imprévisible. le résultat ne peut pas être déterminé avant l'exécution. Combiné avec le théorème d'invariance des chaînes, qui sait où s4 est alloué, donc l'adresse doit être différente. Un diagramme simple est fourni pour clarifier l'idée :

Explication graphique et textuelle détaillée du pool de constantes Javas1 == s9 n'est pas égal, et la raison est similaire, bien que s7 et s8 utilisent des littéraux de chaîne lors de l'attribution de valeurs, lorsqu'ils sont épissés. dans s9, En tant que deux variables, s7 et s8 sont imprévisibles. Après tout, le compilateur est un compilateur et ne peut pas être utilisé comme interpréteur, donc aucune optimisation n'est effectuée lors de l'exécution, la nouvelle chaîne fusionnée par s7 et s8 sera. à l'adresse dans le tas. Je ne suis pas sûr, cela ne peut pas être la même que l'adresse s1 dans le pool constant de la zone de méthode.

Explication graphique et textuelle détaillée du pool de constantes Java

s4 == s5 n'a plus besoin d'explication, absolument pas égal, les deux sont dans le tas, mais ont des adresses différentes.

s1 == s6 Ces deux égalités sont entièrement dues à la méthode interne s5 est dans le tas et le contenu est Hello. La méthode interne tentera d'ajouter la chaîne Hello au pool de constantes et de la renvoyer. le pool de constantes. Comme il existe déjà une chaîne Hello dans le pool de constantes, la méthode interne renvoie directement l'adresse ; et s1 pointe déjà vers le pool de constantes lors de la compilation, donc s1 et s6 pointent vers la même adresse et sont égaux.

À ce stade, nous pouvons tirer trois conclusions très importantes :

Nous devons prêter attention au comportement au moment de la compilation afin de mieux comprendre le pool constant.

Les constantes du pool de constantes d'exécution proviennent essentiellement du pool de constantes de chaque fichier de classe.

Lorsque le programme est en cours d'exécution, le jvm n'ajoutera pas automatiquement de constantes au pool de constantes, sauf si vous ajoutez manuellement des constantes au pool de constantes (par exemple en appelant la méthode interne).

Ce qui précède concerne uniquement les pools de constantes de chaîne. En fait, il existe également des pools de constantes entières, des pools de constantes à virgule flottante, etc., mais ils sont tous similaires, sauf que vous ne pouvez pas ajouter manuellement de constantes à la constante de type numérique. pool. Les constantes du pool de constantes ont été déterminées au démarrage du programme. Par exemple, la plage de constantes dans le pool de constantes entières est : -128~127. Seuls les nombres de cette plage peuvent être utilisés dans le pool de constantes.

Pratique

Après avoir dit tant de théorie, abordons le véritable bassin constant.

Comme mentionné précédemment, il existe un pool de constantes statiques dans le fichier de classe. Ce pool de constantes est généré par le compilateur et est utilisé pour stocker les littéraux dans les fichiers source Java (cet article se concentre uniquement sur les littéraux). Il y a le code java suivant :

 String s = "hi";

为了方便起见,就这么简单,没错!将代码编译成class文件后,用winhex打开二进制格式的class文件。如图:

Explication graphique et textuelle détaillée du pool de constantes Java

简单讲解一下class文件的结构,开头的4个字节是class文件魔数,用来标识这是一个class文件,说白话点就是文件头,既:CA FE BA BE。

紧接着4个字节是java的版本号,这里的版本号是34,因为笔者是用jdk8编译的,版本号的高低和jdk版本的高低相对应,高版本可以兼容低版本,但低版本无法执行高版本。所以,如果哪天读者想知道别人的class文件是用什么jdk版本编译的,就可以看这4个字节。

接下来就是常量池入口,入口处用2个字节标识常量池常量数量,本例中数值为00 1A,翻译成十进制是26,也就是有25个常量,其中第0个常量是特殊值,所以只有25个常量。

常量池中存放了各种类型的常量,他们都有自己的类型,并且都有自己的存储规范,本文只关注字符串常量,字符串常量以01开头(1个字节),接着用2个字节记录字符串长度,然后就是字符串实际内容。本例中为:01 00 02 68 69。

接下来再说说运行时常量池,由于运行时常量池在方法区中,我们可以通过jvm参数:-XX:PermSize、-XX:MaxPermSize来设置方法区大小,从而间接限制常量池大小。

假设jvm启动参数为:-XX:PermSize=2M -XX:MaxPermSize=2M,然后运行如下代码:

//保持引用,防止自动垃圾回收
List<String> list = new ArrayList<String>();
        
int i = 0;
        
while(true){
    //通过intern方法向常量池中手动添加常量
    list.add(String.valueOf(i++).intern());
}

程序立刻会抛出:Exception in thread "main" java.lang.outOfMemoryError: PermGen space异常。PermGen space正是方法区,足以说明常量池在方法区中。

在jdk8中,移除了方法区,转而用Metaspace区域替代,所以我们需要使用新的jvm参数:-XX:MaxMetaspaceSize=2M,依然运行如上代码,抛出:java.lang.OutOfMemoryError: Metaspace异常。同理说明运行时常量池是划分在Metaspace区域中。具体关于Metaspace区域的知识,请读者自行搜索。

更多java知识请关注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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer