You can often see discussions on the memory allocation of Java strings when running in major sections on the Internet, such as: String a = "123", String b = new String("123"), where are these two forms of strings stored? In fact, the literal value of string "123" in these two forms is neither stored on the stack nor on the heap at runtime. They are stored in a certain constant area in the method area, and only one copy is retained in memory for the same string literal value. We will analyze it with examples below.
1. The == operator is used in two cases where two string reference comparisons are compared:
public class StringTest { public static void main(String[] args) { //part 1 String s1 = "i love china"; String s2 = "i love china"; System.out.println("result:" + s1 == s2);//The program run result is true //part 2 String s3 = new String("i love china"); String s4 = new String("i love china"); System.out.println("result:" + s3 == s4);//The program run result is false }}We know that the == operator in Java compares the values of variables. The value of the variable corresponding to the reference type stores the address of the reference object. Here String is the reference type, and the values of the four variables here actually store the addresses of the string. The execution result for part2 is obvious, because the new operator will cause jvm to create new objects in the heap at runtime, and the addresses of the two different objects are different. However, from the execution result of part1, it can be seen that s1 and s2 are the same address pointed to. So where are the strings pointed to by variables s1 and s2 stored? How does jvm handle strings? Similarly, for different string objects in the heap pointed to by variables s3 and s4, will they save a "i love china" string in their own object space? In order to understand how jvm handles strings, first we look at the bytecode instructions generated by the java compiler. Through the bytecode instruction, we analyze what operations will be performed by jvm.
2. The following is some bytecode information generated by the program. The red marks the part we need to pay attention to.
Constant pool: #1 = Class #2 // StringTest #2 = Utf8 StringTest #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Utf8 <init> #6 = Utf8 ()V #7 = Utf8 Code #8 = Methodref #3.#9 // java/lang/Object."<init>":()V #9 = NameAndType #5:#6 // "<init>":()V #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 LStringTest; #14 = Utf8 main #15 = Utf8 ([Ljava/lang/String;)V #16 = String #17 // i love china Reference to string address #17 = Utf8 i love china #18 = Fieldref #19.#21 // java/lang/System.out:Ljava/io/PrintStream; #19 = Class #20 // java/lang/System #20 = Utf8 java/lang/System #21 = NameAndType #22:#23 // out:Ljava/io/PrintStream; #22 = Utf8 out #23 = Utf8 Ljava/io/PrintStream; #24 = Class #25 // java/lang/StringBuilder #25 = Utf8 java/lang/StringBuilder #26 = String #27 // result: #27 = Utf8 result:#28 = Methodref #24.#29 // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V#29 = NameAndType #5:#30 // "<init>":(Ljava/lang/String;)V#30 = Utf8 (Ljava/lang/String;)V#31 = Methodref #24.#32 // java/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder;#32 = NameAndType #33:#34 // append:(Z)Ljava/lang/StringBuilder;#33 = Utf8 append#34 = Utf8 (Z)Ljava/lang/StringBuilder;#35 = Methodref #24.#36 // java/lang/StringBuilder.toString:()Ljava/lang/String;#36 = NameAndType #37:#38 // toString:()Ljava/lang/String;#37 = Utf8 toString#38 = Utf8 ()Ljava/lang/String;#39 = Methodref #40.#42 // java/io/PrintStream.println:(Ljava/lang/String;)V#40 = Class #41 // java/io/PrintStream#41 = Utf8 java/io/PrintStream#42 = NameAndType #43:#30 // println:(Ljava/lang/String;)V#43 = Utf8 println#44 = Class #45 // java/lang/String#45 = Utf8 java/lang/String#46 = Methodref #44.#29 // java/lang/String."<init>":(Ljava/lang/String;)V#47 = Utf8 args#48 = Utf8 [Ljava/lang/String;#49 = Utf8 s1#50 = Utf8 Ljava/lang/String;#51 = Utf8 s2#52 = Utf8 s3#53 = Utf8 s4#54 = Utf8 StackMapTable#55 = Class #48 // "[Ljava/lang/String;"#56 = Utf8 SourceFile#57 = Utf8 StringTest.java............//The bytecode instruction for the corresponding method is explained and executed by the jvm runtime. public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=5, args_size=1 0: ldc #16 // String i love china, this directive refers to the symbol at #16 of the constant pool, and here pushes the string "ilove china" symbol to the top of the stack. This instruction corresponds to the following instruction 2. String s1 = "i love china" statement 2 in the program: store_1 // Assign the object reference at the top of the stack to the local variable 1. 3: ldc #16 // String i love china, the instruction at the same 0 points to a constant at the same symbol reference. This instruction and the following instruction 5 correspond to the String s2 = "i love china" statement in the program. 5: store_2 // Assign object references to local variables at the top of the stack 2. 6: getstatic #18 // Field java/lang/System.out:Ljava/io/PrintStream; 9: new #24 // class java/lang/StringBuilder 12: dup 13: ldc #26 // String result: 15: invokespecial #28 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 18: aload_1 19: aload_2 20: if_acmpne 27 //Pop up the two object references on the top of the stack to compare whether they are equal or not, go to directive 27, execute, execute the next instruction equally 23: iconst_1 24: goto 28 27: iconst_0 28: invokevirtual #31 // Method java/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder; 31: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 34: invokevirtual #39 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 37: new #44 // class java/lang/String, create an object, which is located at the reference of the constant pool #44, here is the String object, and the object reference is pushed to the top of the stack. 40: dup //Copy a copy of the object on the top of the stack and push it to the top of the stack. 41: ldc #16 // String i love china, same as 0, 3 instructions. 43: invokespecial #46 // Method java/lang/String."<init>":(Ljava/lang/String;)V 46: store_3 47: new #44 // class java/lang/String//Create an object and push the object to the top of the stack 50: dup 51: ldc #16 // String i love china, push the symbol of the string to the top of the stack. 53: invokespecial #46 // Method java/lang/String."<init>":(Ljava/lang/String;)V, call the init initialization method of the object according to the corresponding object reference at the top of the stack and the string reference, initialize the string object 56: store 4 // Assign the object reference to the variable 4. 58: getstatic #18 // Field java/lang/System.out:Ljava/io/PrintStream; 61: new #24 // class java/lang/StringBuilder 64: dup 65: ldc #26 // String result: 67: invokespecial #28 // Method java/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder; 84: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder; 84: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/StringBuilder; 87: invokevirtual #39 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 90: return.........LineNumberTable:line 7: 0line 8: 3line 9: 6line 11: 37line 12: 47line 13: 58line 14: 90LocalVariableTable:Start Length Slot Name Signature91 0 args [Ljava/lang/String;//Local variable 088 1 s1 Ljava/lang/String; //Local variable 185 2 s2 Ljava/lang/String;//Local variable 244 3 s3 Ljava/lang/String;//Local variable 333 4 s4 Ljava/lang/String;//Local variable 4
The red part of the bytecode is related to our discussion. Through the generated bytecode, we can draw the following conclusions for the example program.
1). When the java compiler compiles the program into bytecode, the string constant "i love china" encountered first determines whether it exists in the bytecode constant pool. If it does not exist, it will not create it. That is, an equal string, only one copy can be retained. It can be found through symbolic references, so that the string variables s1 and s2 in the program point to the same string constant in the constant pool. At runtime, jvm will store string constants in the bytecode constant pool in the location of the method area commonly called the constant pool, and the string is accessed through indexes in the form of a character array. jvm points the relative reference address of the string pointed to by s1 and s2 to the actual memory address of the string at runtime.
2). For String s3 = new String("i love china"), String s4 = new String("i love china"), from the bytecode, it can be seen that it calls the new instruction. jvm will create two different objects at runtime, and s3 and s4 point to different object addresses. Therefore, the result of s3==s4 comparison is false.
Secondly, for the initialization of s3 and s4 objects, it is seen from the bytecode that the init method of the object is called and the reference "i love china" in the constant pool is passed. So what is the creation of the String object and the initialization? We can check the source code of the String and the bytecode generated by the String object to better understand whether the string is copied inside the object or the reference directly to the address of the constant pool corresponding to the string is pointed to.
3. Part of the source code of the String object:
<SPAN style="FONT-SIZE: 14pt">public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 public String() { this.value = new char[0]; }</SPAN> <SPAN style="BACKGROUND-COLOR: #ffffff; FONT-SIZE: 18pt"> public String(String original) { this.value = original.value; this.hash = original.hash; } </SPAN>From the source code, we see that there is an instance variable char value[] in the String class. Through the construction method, we can see that the object does not perform copying operations when initializing, but only assigns the address reference of the passed string object to the instance variable value. From this we can initially conclude that even when a string object is created using new String("abc"), space is allocated for the object in the memory heap, but no information about "abc" itself is stored on the heap, but the reference to the "abc" string is initialized within its instance variable to the "abc" string. In fact, this is also to save memory storage space and improve program performance.
4. Let’s take a look at the bytecode information of the String object:
public java.lang.String(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: newarray char 8: putfield #2 // Field value:[C 11: return LineNumberTable: line 137: 0 line 138: 4 line 139: 11 public java.lang.String(java.lang.String); descriptor: (Ljava/lang/String;)V flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 //Push the local variable 0 to the top of the stack, a reference to its own object. 1: invokespecial #1 // Method java/lang/Object."<init>":()V Pop up the stack top object to refer to the initialization method at #1 of the object. 4: aload_0 //Push the reference of its own object to the top of the stack. 5: aload_1 //The passed string reference push to the top of the stack. 6: getfield #2 // Field value:[C // Pop up the string reference at the top of the stack and assign it to the instance variable at #2, and store it on the stack. 9: putfield #2 // Field value:[C // Pop up the string reference at the top of the stack and the object itself and assign the string reference to the instance variable of the object itself. 12: aload_0 13: aload_1 14: getfield #3 // Field hash:I 17: putfield #3 // Field hash:I 20: return
From the perspective of bytecode, we can conclude that new String("abc") performs assignments of string references when constructing a new object, rather than copying of strings. The above is an analysis and summary of the memory allocation of strings from the perspective of source code and byte code.
The above analysis and summary of Java string memory allocation (recommended) is all the content I share with you. I hope you can give you a reference and I hope you can support Wulin.com more.