This article is participating in the “Java Theme Month – Java Brush questions card”, activity link

The title

Address your technical blind spots in JVM constant pools

knowledge

What is a constant

Constants are represented by final modified member variables whose values cannot be changed once given.

  • Final modifies three types of variables: static variables, instance variables, and local variables, representing three types of constants.

Method areas in the JVM

The JVM’s methods section holds the class version, fields, methods, interfaces, and constant pools. The constant pool stores literal and symbolic references.

Constant pools in Java

There are actually two forms: static constant pools and runtime constant pools.

Static constant pool

Static constant pool, that is, the constant pool in the class file. The constant pool in the class file contains not only string (number) literals, but also class and method information, which occupies most of the space of the class file.

A class constant pool

  • When a Java file is compiled into a class file, what we call a class constant pool is generated in the class file.

  • Constant Pool table Constant Pool table constant pool table constant pool table constant pool table constant pool table To hold the compiler to generate various kinds of literal 】 【 (a text string, is declared as final values of the constants, basic data types) and symbolic reference 】 【 (classes and the fully qualified name of the interface, the names of the name of the field and method descriptors, and descriptor), this part will be in after class loading into the method of runtime constants in the pool.

The constant pool holds symbolic information that the JVM relies on when executing instructions. All entries in the constant pool have the following common format:

cp_info { u1 tag; // cp_info single-byte flag bit U1 info[]; // Two or more bytes represent information about this constant. The format of the information is determined by the value of the tag.Copy the code

The supported types are as follows:

Take CONSTANT_Class, which is used to represent a class or interface in the following format:

CONSTANT_Class_info {
 u1 tag;
 u2 name_index;
Copy the code
  • The CONSTANT_Class_info type consists of a tag and a name_index.

    • Tag: This value is CONSTANT_Class (7) and represents references that belong to a class (CONSTANT_Fieldref stands for field references)

    • The index in name_index indicates that it is an index and refers to CONSTANT_UTF8_info.

  • CONSTANT_Utf8_info is used to represent the value of a character constant as follows:

CONSTANT_Utf8_info {
 u1 tag;
 u2 length;
 u1 bytes[length];
}
Copy the code
  • Tag is represented by CONSTANT_Utf8 (1), which indicates that it belongs to a string worthy of reference;

  • Length: specifies the length of bytes[] array; The bytes[] array references the last length as its length. Character constants are represented by the improved UTF-8 encoding.

One more thing: for static constant pools we need to know that they exist in the compiler, and if anything, at runtime constants are allocated by the JVM after the class file is loaded.


Run-time constant pool

The JVM loads the constant pool of the class file into memory and stores the constant pool in the method area after class loading.

  • Runtime constant pool relative to the Class file another important feature of the constant pool is dynamic, the Java language does not require constant must only compile time to produce, is not preset constant pool into the Class file content can enter method area runtime constant pool, runtime might also put new constants in a pool, One feature that developers use most is the Intern () method of the String class.

  • When a class is loaded into memory, the JVM stores the contents of the class constant pool into the runtime constant pool, which is also one for each class.

    • The runtime constant pool is used to dynamically retrieve class information, including: class file meta-information description, compiled code data, reference type data, and other data from the class file constant pool.

    • Class constant pools store literals and symbolic references, meaning that they do not store instances of objects, but symbolic reference values of objects.

    • After resolve, which replaces symbolic references with direct references, the resolve process checks the string pool to ensure that the string referenced by the runtime constant pool is the same as the string referenced by the string constant pool.

String Constant pool

The contents of the string constant pool are generated in the heap after class loading, validation, and preparation, and then the reference value of that string object instance is stored in the String pool (remember: In jdk1.8, the string pool stores reference values instead of specific instance objects, which are stored in a block of heap. There is only one string pool in each HotSpot VM instance, shared by all classes.

  • The contents of the string pool are stored in the string constant pool after class loading, validation, and preparation. The implementation of the string constant pool will not be expanded here and will be explained in a special article later.

  • The processing mechanism of the string constant pool is described in the previous article, and only one copy is stored, shared by all classes. The basic flow is to check if a string exists in the constant pool before creating it, get a reference if it does, create and store it if it doesn’t, and return a new object reference.

Different versions of the string constant pool

The location of the string constant pool changes as JDK versions evolve, and we’ll use a diagram to illustrate it below.

In JDK1.7 the string constant pool and static variables are taken from the method area to the heap, and the rest of the run-time constant pool is still in the method area, which is the permanent generation in hotspot.

In JDK8 hotspot, the Metaspace is removed. The string constant pool is still in the heap, and the runtime constant pool is still in the method area, but the method area implementation is changed from the permanent generation to Metaspace.

Points to note:

The benefits of constant pools

Constant pool is to avoid frequent creation and destruction of objects that affect system performance, and it realizes object sharing.

The string constant pool, for example, puts all string literals into one constant pool at compile time.

  1. Memory saving: All the same string constants in the constant pool are merged and occupy only one space.

  2. Save runtime: == is faster than equals() when comparing strings. For two reference variables, only == is used to determine whether the references are equal, which can also determine whether the actual values are equal.

extends

String s1=new String("abc"); 
Copy the code

The first thing you need to understand is the constant pool. This is a special shared area where you can put things like literate, Class, things that can be shared in memory that don’t change very often.

  • When your Class is loaded by the ClassLoader, your “ABC” is read as a constant, creating a shared “ABC” in the String constant pool.

  • Then, when new String(” ABC “) is called, the new String(” ABC “) is created in the heap;

Consider the class loading phase and the actual execution time.

  • Class loading is done only once for a class. ABC “is already created and hosted when the class is loaded (if the class already has an” ABC “string hosted before the class is loaded, you don’t need to create it again, just use the hosted instance of” ABC “). Hosted strings are placed in a globally shared string constant pool.

  • The String instance corresponding to the “ABC” literal is fixed and will not be created again. So this code makes a copy of the object in the constant pool and places it in the heap, and gives S1 a reference to the object in the heap.


public class Test{
    public static String a = "a";
    public static void main(a){
        String b = "b"; }}Copy the code

Use the Java decompiler tool to decompilate and run javap-verbose test. cass

You can see that both static String variables are put into the constant pool


public class Test2{
    public static String str = "laji" + "MySQL";
    public static void main(a){}}Copy the code

Analyze a wave before compiling, which is a static String Constant and should appear in the Constant Pool

There are no separate string constants for two elements, only concatenated data.


public class Test2_2{
    public static void main(String[] args){
        String string1 = "laji";  
        String string2 = "MySQL";  
        String string3 = string1+string2;  
        String string4 = string1+"C"; }}Copy the code

  • Two String (literal) constants that do + directly are not put into the String constant pool. Instead, the result of the operation is put directly into the constant pool.

  • String literal constants declared first are put into the constant pool, but operations performed using references to literals are not put into the constant pool

To summarize, the JVM optimizes operations on String constants to include only the result if undeclared; If it has been declared, only declarations will be put.


public class Test3{
    public static void main(String[] args){
        String str = "laji";
        String str2 = new String("MySQL");
        String str3 = new String("laji");
        System.out.println(str==str3);// The result is false after running}}Copy the code

First of all, when you’re instantiating an object in the heap, how does it end up in the constant pool?

In this case, “MySQL” does not appear as string constants in the constant pool, but as literals. The instantiation operation (the process of new) is performed at runtime, and the corresponding object is not generated in the heap at compile time.

The result is false because STR points to “laji” in the constant pool, whereas STR3 points to “laji” in the heap. == Compares references (addresses), which is false


public class Test4{
    public static void main(String[] args){
        String str = "laji";
        String str2 = new String("laji");
        String str3 = null;
        System.out.println(str==str2);// The result is false after running
        str3 = str2.intern();
        System.out.println(str==str3);// The result is true after running}}Copy the code

Obviously, STR3 gets the value from the string constant pool when initialized.


In JDK1.7, the JVM removed the String constant section from the method section; In JDK1.8, the JVM moved the String constant pool to the heap, eliminating the “permanent generation” and replacing it with Metaspace.

import java.util.ArrayList;

public class TestString {

    public static void main(String[] args) {
            String str = "abc";  
            char[] array = {'a'.'b'.'c'};  
            String str2 = new String(array);  
            // Use intern() to put the str2 string contents into the constant pool
            str2 = str2.intern();  
            // This comparison is used to illustrate string literal constants and us
            // Use intern to process strings in the same placeSystem.out.println(str == str2); }}Copy the code

To summarize

  • Static variables (static constant pool) are stored in a class file in the compiler. You can use the javap-verbose command to view the contents of the static constant pool when string merging.

  • The string constant pool used to be part of the runtime constant pool, located in the method area, but the two have been separated as JVM versions have evolved. After JDK8, the string constant pool is in the heap, and the runtime constant pool is in the method area.