Understanding Java constant pool and java constant pool

Source: Internet
Author: User

Understanding Java constant pool and java constant pool

The memory model of the JVM runtime data zone consists of five parts:

[1] Method Area
[2] heap
[3] JAVA stack
[4] PC register
[5] local method Stack

For String s = "haha", its VM commands:
0: ldc #16; // String haha
2: astore_1
3: return

For the above VM commands, their respective instructions are described in "deep into Java Virtual Machine" (combined with the above instance ):

Ldc Command Format: ldc, index

Ldc instruction process:

To execute the ldc command, JVM first searches for the constant pool entry specified by index. In the constant pool entry pointed to by index, JVM searches for CONSTANT_Integer_info, CONSTANT_Float_info, and CONSTANT_String_info. If these entries are not available, JVM will parse them. For the preceding hahaJVM, The CONSTANT_String_info entry is found, and the reference pointing to the detained String object (generated by the process that parses the entry) is pushed to the operand stack.

Astore_1 Command Format: astore_1

Astore_1 command process:

To execute the astore_1 command, JVM pops up a reference type or returnAddress type value from the top of the operand stack, and then stores the value in a local variable specified by index 1, save the reference type or returnAddress type value to local variable 1.

Return command process:

Return from the method. The return value is void.

My personal understanding:

From the execution process of the preceding ldc command, we can conclude that the value of s is a reference from the detained String object (generated by the process that parses the entry, that is, it can be understood that it is copied from the reference of the detained String object, so my personal understanding is that the value of s exists in the stack. The above is an analysis of the s value, followed by an analysis of the "haha" value. We know that, for String s = "haha" where "haha" is determined during the JAVA program compilation period. To put it simply, the value of haha is after the program is compiled into a class file, it is generated in the class file (you can use the UE editor or other text editing tools to view the haha value in the bytecode file after opening the class file ). During JAVA program execution, the first step is to generate the class file and then load it To the memory for execution by JVM. In this case, the JVM loads this class into the memory. In this case, how does one open up space for the class and store the haha value in the memory?

Here, let's take a look at the structure of the JVM constant pool, which is described in the deep Java Virtual Machine book:

Constant pool

The virtual machine must maintain a constant pool for each mounted type. A constant pool is an ordered set of constants used for this type, including direct constants (string, integer, and floating point constants) and symbolic references to other types, fields, and methods. For a String constant, its value is in the constant pool. The constant pool in JVM exists in the memory as a table. For the String type, there is a fixed-length CONSTANT_String_info table to store the text String value. Note: this table only stores text string values, but does not store symbol references. Here, we should have a clear understanding of the storage location of string values in the constant pool.

After introducing the concept of JVM constant pool, let's talk about the memory distribution position of the "haha" value. The haha value is actually before the class file is loaded into the memory by JVM and the engine parses the ldc command and executes the ldc command, JVM has allocated space for the haha string in the CONSTANT_String_info table of the constant pool to store the haha value. Since the haha String constant is stored in the constant pool, according to the description in "Deep Java Virtual Machine": the constant pool is part of the type information, and the type information is each reprinted type, this type is reflected in the JVM Memory Model and exists in the Method Area of the JVM memory model, that is, the constant pool concept in this type information exists in the method area, the method area is allocated by JVM In the heap of the JVM memory model. Therefore, the value of haha should exist in the heap space.

For String s = new String ("haha"), its JVM command:
0: new #16; // class String
3: dup
4: ldc #18; // String haha
6: invokespecial #20; // Method java/lang/String. "" :( Ljava/lang/String;) V
9: astore_1
10: return

For the above VM commands, their respective instructions are described in "deep into Java Virtual Machine" (combined with the above instance ):

New Command Format: new indexbyte1, indexbyte2

New instruction process:

To execute the new command, Jvm generates an unsigned 16-bit index pointing to the constant pool through calculation (indextype1 <8) | indextype2. Then, JVM searches for the constant pool entry based on the calculated index. The entry to the constant pool to which the index points must be CONSTANT_Class_info. If this entry does not exist, JVM will parse this constant pool entry, which must be a class. JVM allocates enough space for the new object image from the heap and sets the instance variable of the object as the default value. At last, JVM pushes the reference objectref pointing to the new object to the operand stack.

Dup Command Format: dup

Dup command process:

To execute the dup command, JVM copies the long-character content at the top of the operand stack, and then pushes the copied content to the stack. This command can copy any unit-length value from the top of the operand stack. But never use it to copy one of the two character lengths (long or double) at the top of the operand stack. In the preceding example, copy and reference objectref. In this case, two references exist in the operand stack.

Ldc Command Format: ldc, index

Ldc instruction process:

To execute the ldc command, JVM first searches for the constant pool entry specified by index. In the constant pool entry pointed to by index, JVM searches for CONSTANT_Integer_info, CONSTANT_Float_info, and CONSTANT_String_info. If these entries are not available, JVM will parse them. For the preceding haha, JVM finds the CONSTANT_String_info entry and pushes the reference pointing to the detained String object (generated by the process that parses the entry) to the operand stack.

Invokespecial Command Format: invokespecial, indextype1, indextype2

Invokespecial command process: for this class, this command is used to call the instance initialization method. For details about the length of this instruction, refer to the description in deep Java virtual machine. In the above example, the constructor of the String class is called through one of the references to initialize the object instance, so that another identical reference points to the initialized object instance, then, the operand stack is displayed in the previous reference.

Astore_1 Command Format: astore_1

Astore_1 command process:

To execute the astore_1 command, JVM pops up a reference type or returnAddress type value from the top of the operand stack, and then stores the value in a local variable specified by index 1, save the reference type or returnAddress type value to local variable 1.

Return command process:

Return from the method. The return value is void.

To execute the astore_1 command, JVM pops up a reference type or returnAddress type value from the top of the operand stack, and then stores the value in a local variable specified by index 1, save the reference type or returnAddress type value to local variable 1.


From the preceding six commands, we can see that haha in String s = new String ("haha"); is stored in the heap space, while s is in the operand stack.
The above is an analysis and understanding of the memory conditions of s and haha values; then, how many objects have been created for the String s = new String ("haha"); statement?
In my understanding, "haha" itself is an object in the constant pool. When new String () is executed at runtime, the objects in the constant pool are copied and put in the heap, and assign the reference of this object in the heap to s. Therefore, this statement creates two String objects.


The following are some FAQs related to String:

Usage and understanding of final in String
Final StringBuffer a = new StringBuffer ("111 ");
Final StringBuffer B = new StringBuffer ("222 ");
A = B; // This sentence cannot be compiled

Final StringBuffer a = new StringBuffer ("111 ");
A. append ("222"); // compiled

It can be seen that final is only valid for the referenced "value" (that is, the memory address), which forces the reference to point only to the object initially pointed to. changing its direction will lead to compilation errors. Final is not responsible for the changes to the objects it points.

Several examples of String constant pool problems

The following is a comparative analysis and understanding of several common examples:
[1]
String a = "a1 ";
String B = "a" + 1;
System. out. println (a = B); // result = true
String a = "atrue ";
String B = "a" + "true ";
System. out. println (a = B); // result = true
String a = "a3.4 ";
String B = "a" + 3.4;
System. out. println (a = B); // result = true

Analysis: JVM connects the "+" Number of string constants. During the program compilation period, the JVM optimizes the "+" connection of the constant string to the connected value, take "a" + 1 as an example. After the compiler is optimized, it is already a1 in the class. The value of its String constant is determined during compilation, so the final result of the above program is true.

[2]
String a = "AB ";
String bb = "B ";
String B = "a" + bb;
System. out. println (a = B); // result = false

Analysis: JVM references strings. Due to the existence of string references in the "+" connection of strings, the referenced values cannot be determined during program compilation, that is, "a" + bb cannot be optimized by the compiler. It is dynamically allocated only during the running period and assigned the new connection address to B. Therefore, the result of the above program is false.

[3]
String a = "AB ";
Final String bb = "B ";
String B = "a" + bb;
System. out. println (a = B); // result = true

Analysis: The only difference from [3] Is that the bb string is decorated with final. For final modified variables, it is parsed as a local copy of a constant value during compilation and stored in its own constant pool or embedded in its byte code stream. Therefore, "a" + bb "and" a "+" B "have the same effect. Therefore, the result of the above program is true.

[4]
String a = "AB ";
Final String bb = getBB ();
String B = "a" + bb;
System. out. println (a = B); // result = false
Private static String getBB (){
Return "B ";
}

Analysis: JVM cannot determine the value of bb in string reference during compilation. Only after the method is called during the runtime, dynamically connect the return value of the method with "a" and assign the address B. Therefore, the result of the above program is false.

The above four examples show that:
String s = "a" + "B" + "c ";
It is equivalent to String s = "abc ";

String a = "";
String B = "B ";
String c = "c ";
String s = a + B + c;

This is different. The final result is equal:
StringBuffer temp = new StringBuffer ();
Temp. append (a). append (B). append (c );
String s = temp. toString ();

From the above analysis results, it is not difficult to infer the cause of the inefficiency of the String using the join operator (+), such as the Code:

Public class Test {
Public static void main (String args []) {
String s = null;
For (int I = 0; I <100; I ++ ){
S + = "";
}
}
}

Every time you do the plus sign (+), a StringBuilder object is generated and then thrown away after append. When the next loop arrives, A StringBuilder object is generated again, and then the append string is generated. The loop ends until the end. If we directly use the StringBuilder object for append, we can save N-1 time to create and destroy objects. Therefore, for applications that require string connection in a loop, the append operation is generally performed using the StringBuffer or StringBulider object.

The intern method of the String object is described as follows:

Public class Test4 {
Private static String a = "AB ";
Public static void main (String [] args ){
String s1 = "";
String s2 = "B ";
String s = s1 + s2;
System. out. println (s = a); // false
System. out. println (s. intern () = a); // true
}
}

Java is used here as a constant pool problem. For the s1 + s2 operation, a new object is actually created in the heap, and s stores the content of the new object in the heap space, therefore, the values of s and a are not equal. When the s. intern () method is called, the address value of s in the constant pool can be returned. Because the value of a is stored in the constant pool, the values of s. intern and a are equal.


What is the constant stored in the JAVA constant pool?

And strings and constants

Static Zone

Relationship between JAVA basic type variables and constant pool

1. in Java, you can understand that all variables, including basic and reference types, are stored in the stack, each variable in the stack contains the type, name, and value, except that the value of the basic type variable is a specific value, and the value of the referenced type variable is the address of the object in the heap.

2. The constant pool exists to avoid repeated instantiation of a constant value. It seems to be mainly used for string constants. For example, declare String a = "abc" and "abc" "is a String constant. During the declaration process, check whether there are objects such as" abc "in the constant pool, if no value exists, it is instantiated and saved to the constant pool, and then the reference (or handle, address) is assigned to a. If String B = "abc" is declared ", B References an existing object in the constant pool. In the above case, the value of a = B is true, because they reference the same object. If you declare String a = new String ("abc"); String B = new String ("abc");, the value of a = B is false, because new objects are created for a and B respectively.

3. the constant pool should not be used for basic types, because the values of basic types exist in the stack. in Java, the operation, judgment, and assignment of basic types of variables are all values, there is no operation on the address, for example: int a = 1; int B = 2; a = B; this is to assign the value of B to a, rather than a references B;

4. I have not verified the lifecycle of the constant pool.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.