About the body Global string pool Class constant pool Runtime constant pool Pool) to summarize the association between the three constant pools

preface

The memory of a Java JVM is divided into three areas: heap, stack, and Method, also known as static storage.

In the learning process will often hear the term constant pool, in the section about data when doing the = = comparison mentioned string constant pool, by the query Constant pool doesn’t belong to the heap, and does not belong to the stack memory, then constant pool may be method and area have relations, so read book covering the JVM, understand the constant pool and the method’s association, At the same time, the classification of constant pool is also understood.

All the code in this article is based on JDK1.8.

The body of the

Before we explore the types of constant pools, we need to understand what constants are.

  • Member variables decorated with final are constants that cannot be changed once given!
  • There are three types of variables that final modifies: static variables, instance variables, and local variables, which represent three types of constants, respectively.

In Java memory allocation, there are three types of constant pools:

Global string pool (string pool also called String Literal pool)

The location of the string constant pool in the Java memory region

  • In JDK6.0 and earlier, the string constant pool was in the Perm Gen area (the method area), while the constant pool stored the object.
  • In JDK7.0, the string constant pool was moved to the heap. The constant pool stores references. In JDK8.0, the permanent generation (method area) is replaced by the meta space.

What is a string constant pool?

The string Pool functionality implemented in HotSpot VM is a StringTable class, which is a Hash table with a default size of 1009; It contains a reference to the resident string (not the resident string instance itself). That is, some ordinary string instances are referred to by this StringTable as resident strings. There is only one copy of this StringTable per HotSpot VM instance and it is shared by all classes.

StringTable is essentially a HashSet

. This is a pure runtime structure and is lazily maintained. Note that it only stores references to instances of Java.lang. String, not the contents of the String object. Note that it only holds the reference from which to get the concrete String.

In JDK6.0, StringTable has a fixed length of 1009, so if there are too many strings in the String Pool, it will cause hash conflicts and make the list too long. When String#intern() is called, it has to go through the list one by one, resulting in performance degradation.

In JDK7.0, the StringTable length can be specified with an argument:

-XX:StringTableSize=66666

Copy the code

Class Constant pool

As we all know, in addition to the class version, field, method, interface, and other description information, there is a constant pool table information. Used to hold various literals and Symbolic References generated by the compiler. Literals are closer to the concept of constants at the Java language level, such as text strings, constant values that are declared final, and so on. Symbolic references are a compilation principle concept that includes the following three types of constants:

  • Fully qualified names of classes and interfaces
  • The name and descriptor of the field
  • The name and descriptor of the method

Each constant in the constant pool is a table. There are 11 different kinds of table structure data as shown in the following table. The first bit at the beginning of each table is a byte flag bit (value 1-12), which indicates the type of constant the current constant belongs to.


Each type of constant has a different structure, which I won’t discuss in this article. This article focuses on distinguishing between the three constant pools. (For more information on the data structure of each constant type, see Chapter 6 of Understanding the Java Virtual Machine.
In fact, he did not understand, the follow-up back to fill the pit).

Runtime Constant pool

The runtime constant pool is part of the method area.

When a Java file is compiled into a class file, the class constant pool is generated. When is the runtime constant pool generated?

When the JVM executes a class, it must go through three stages: load, join, and initialize. Join includes validation, prepare, and resolve. Once the class is loaded into memory, the JVM stores the contents of the class file constant pool into the run-time constant pool, so there is also one for each class. As mentioned above, the class constant pool stores literals and symbolic references. That is, they do not store instances of objects, but rather symbolic references to them. The resolve process will query the global string pool, known as the StringTable, to ensure that the string referenced in the run-time constant pool is the same as the string referenced in the global string pool.

Association between the three constant pools

The string constant pool is also involved in JVM execution.

During class loading, the JVM creates these in the heapclassString object instance in the file constant pool and hosts its reference in the string constant pool. The concrete inresolvePhase execution. These constants are shared globally.

Copy the code

The resolve phase does not immediately create the object and host the reference in the string constant pool as you might expect. The JVM specification explicitly specifies that the resolve phase can be lazy.

There are two types of Class file constant pool entries in the JVM specification: CONSTANT_Utf8 and CONSTANT_String. The former is a String of type utF-8, and the latter is a String of type, but it does not directly hold the contents of the String. Instead, it holds only an index. The other pool entry specified by this index must be a constant of type CONSTANT_Utf8. This is where you actually hold the contents of the string.

In HotSpot VM, in the runtime constant pool,

CONSTANT_Utf8 -> Symbol* (a pointer to oneSymbolC++ object of type, the contents of which are UTF in the same format as the Class file- 8 -Encoded string)

CONSTANT_String -> java.lang.String(a reference to an actual Java object whose C++ type is oop)

Copy the code

CONSTANT_Utf8 is completely created during class loading, and CONSTANT_String is lazy resolve. For example, it is resolved when the LDC directive that first references the item is first executed. If it is not resolved, HotSpot VM will call its type JVM_CONSTANT_UnresolvedString and its contents will be just an index as in the Class file. After resolve, the item’s constant type will become the final JVM_CONSTANT_String and the content will become the actual OOP.

It should be clear that, according to HotSpot VM’s implementation, when a class is loaded, string literals go into the run-time constant pool of the current class, not into the global string constant pool (i.e., there is no reference in StringTable and no corresponding object is generated in the heap). Resolve, as mentioned above, queries the global string pool and replaces the symbolic reference with a direct reference. (Literal and symbolic references are stored in the run-time constant pool when the class loads, but in the case of lazy resolve literals, the action is done after resolve.)

The LDC directive is here to learn about lazy Resolution

Simply put, it is used to push a String constant value from the constant pool to the top of the stack.

Take the following code as an example:

    public static void main(String[] args) {

        String s = "abc";

    }

Copy the code

For example, if the code file is test. Java, first open the Dos window in the file directory, run javac test. Java to compile, and then enter javap -verbose Test to check the compiled class file as follows:


Use the LDC instruction to load “ABC” to the top of the operand stack, and then use astore_1 to assign it to our local variable s, and then return.

In the resolve phase (constant pool resolution), string literals are created and their references reside in the pool of string constants, but the resolve is lazy. In other words, there are no real objects, certainly not in the string constant pool, so how does the LDC directive push the value to the top of the stack and do the assignment? Or, to put it another way, since the resolve phase is lazy, there must be a point at which it actually executes. When?

Execution of the LDC instruction is the condition that triggers the Lazy Resolution action

The execution semantics of LDC bytecode here are: Look for the index in the current class’s runtime constant pool (Runtime Pool + ConstantPoolCache in HotSpot VM). Resolve the item if it has not already been resolved, and return the content after resolve. If the StringTable already has a reference to the java.lang.String that matches the content of the String, the resolve process simply returns the reference. Conversely, if StringTable does not have a reference to the matched String instance, a String object with the corresponding content is created in the Java heap, and StringTable records the reference and returns the reference.

It can be seen that whether the LDC instruction needs to create a new String instance depends on whether the StringTable has recorded a reference to the corresponding String when the LDC instruction is executed for the first time.

Use the following code to show the analysis:

 public static void main(String[] args) {

           String s1 = "abc";  

        String s2 = "abc";

        String s3 = "xxx";

    }

Copy the code

View the compiled class file as follows:

Insert the picture description here


3. To show in a graphical manner:


Insert the picture description here


String s1 = "abc";The resolve process finds no reference to “ABC” in the string constant pool, creates a new object in the heap, stores the reference to the object in the string constant pool, and returns the reference to S1.

String s2 = “abc”; The resolve process will see that there is already a reference to the “ABC” object in StringTable and return the reference to S2 without creating any objects.

String s3 = “xxx”; As in the first line of code, we create an object in the heap, store a reference to that object into StringTable, and finally return the reference to S3.

Constant pool and the INTERN method

 public static void main(String[] args) {

           String s1 = "ab";/ / # 1

        String s2 = new String(s1+"d");/ / # 2

        s2.intern();/ / # 3

        String s4 = "xxx";/ / # 4

        String s3 = "abd";/ / # 5

        System.out.println(s2 == s3);//true

    }

Copy the code

View the compiled class file as follows:

In the resolve phase, the class is lazy. Therefore, the class will not create an instance object and will not reside in the string constant pool.

The diagram is as follows:


Go to the main method and read each line of code.

  • 1. The LDC directive loads “ab” to the top of the stack. In other words, it creates an “ab” object in the heap and stores a reference to that object in the string constant pool.
  • 2, the LDC instruction loads the “d” to the top of the stack, and then there’s a concatenation, which internally creates a StringBuilder object, append along the way, Finally, call the toString method of the StringBuilder object to get a String (the content is abd, notice that the toString method will new a String), And assign it to S2 (which is still just a reference to the object).Note that there is no reference to the "abd" object in the string constant pool.
  • 3, the intern method first looks in the string constant pool to see if there is a reference to the “abd” object. If not, it saves the reference to the “abd” object in the heap to the string constant pool and returns the reference, but we don’t use a variable to receive it.
  • 4, meaningless, just to show that the “abd” literal in the class file is obtained when #5.
  • 5, the string constant pool already has a reference to the “abd” object, so return the reference directly to S3.

conclusion

1. The global string constant pool has only one copy per VM and contains reference values for string constants.

The class constant pool is created for each class at compile time. At compile time, it holds literal and symbolic references.

3. The run-time constant pool is used to dump symbolic references from each class constant pool into the run-time constant pool after class loading. That is, each class has a run-time constant pool, and after class resolution, the symbolic references are replaced with direct references that are consistent with the reference values in the global constant pool.

The string literals in the class file constant pool enter the run-time constant pool when the class is loaded, and the reference to the string is stored in the resolve phase. In addition, the run-time constant pool is dynamic compared to the class file constant pool. Some constants at compile time, not into the class files is not preset constants content to enter the pool area runtime constant pool, during a run by the method of intern, deposited the string constants in to a string constant pool and runtime constant pool (about which priority into the constant pool, private thought into a string constant pool first, Concrete realization also hopes the great god to instruct).

Refer to the link

  • Juejin. Im/post / 684490…
  • www.zhihu.com/question/55…
  • www.zhihu.com/question/36…