preface

In interviews, we are often asked to call the String intern method and change the memory structure. But have you actually used it in actual production, have you seen how others use it?

The NamingUtils class contains an intern method that uses the String class.

public static String getGroupedName(final String serviceName, final String groupName) { // ... Final String resultGroupedName = groupName + Constants.SERVICE_INFO_SPLITER + serviceName; return resultGroupedName.intern(); }Copy the code

The method is simple: concatenate a string of GrouedName, but why do you call intern at the end? This article will analyze it.

The basic definition of intern method

Let’s look at the definition of the String intern method:

public native String intern();
Copy the code

Discovery is a native method. For the time being, we cannot see its concrete implementation further. In fact, we can also use documentation and some tools to verify the function and operation principle of intern method.

When you call intern, add the string to the constant pool if it does not already exist (compared to equals). If yes, return the corresponding address directly.

We all know that a string constant pool functions like a cache to make programs run faster and save memory. This is presumably what the code calls the Intern method for.

String and constant pool memory structure

To understand what intern does, you have to look at the memory structure of the String String.

Strings are usually created in one of two ways, by the new keyword and by assigning values directly through quotes. These two forms of string creation differ in their memory distribution.

When using double quotes to create a string, it checks the constant pool to see if the string already exists. If not, it creates a constant object in the constant pool and returns the reference address. If so, return it directly.

JDK6 and previous memory structures:

Memory structure for JDK7 and later:

JDK8 and later Perm Space will be changed into a meta-space.

When you use the new keyword to create a string, the object you create is allocated in the heap, and the reference in the stack points to that object.

String str2 = new String("hello");
Copy the code

In the case of a double quoted literal, a constant is generated in the constant pool if the literal “hello” does not exist. If present, the object in the heap points directly to the literal.

JDK6 and previous memory structures:

Memory structure for JDK7 and later:

The new keyword is used to create a String, and several objects are created in memory. Obviously, if “hello” already exists in the constant pool, then only one object will be created in the heap, if not, then string objects will need to be stored in the constant pool. So the answer could be one, it could be two.

Understanding these two basic memory logic and distribution, the basic extension of the situation (interview questions) can be answered.

Such as:

String str1 = "hello"; String str2 = "hello"; System.out.println(str1 == str2); //trueCopy the code

Both objects are stored directly in the constant pool, so the reference address is the same.

Such as:

String s1 = new String("hello"); String s2 = "hello"; String s3 = new String("hello"); System.out.println(s1 == s2); // false System.out.println(s1.equals(s2)); // true System.out.println(s1 == s3); //falseCopy the code

The first output is false because s1 points to the address of the object in the heap and S2 points to the address of the constant pool. The second compares strings stored in the constant pool, they share one, so true; The third s1 and S3 share the “hello” literal from the constant pool, but each has its own object in the heap, so it is false.

Concatenation of strings

String concatenation can be divided into two cases, first look at the direct plus sign concatenation:

String s1 = "hello" + "word"; String s2 = "helloword"; System.out,println(s1 == s2); //trueCopy the code

In this case, the Java compiler optimizes compile time for S1 by concatenating strings and storing them in the constant pool as “HelloWord”. So s1 and S2 both point to the same address in the constant pool.

The other case is a concatenation of non-pure string constants:

String s1 = new String("he") + new String("llo"); 
Copy the code

In this case, the Java compiler also optimizes for string concatenation based on StringBuilder.

The basic process is to create a StringBuilder, call the append method for concatenation, and then call the toString method to generate a string object. The string “hello” generated by the toString method does not exist in the constant pool.

The final memory structure is:

The source code in Nacos was concatenated and then called intern to store the string in the constant pool. Objects in the constant pool are then accessed directly to improve performance.

So what happens when the String class calls intern? So let’s see.

Intern () method of String

We’ve already covered the functionality of the string.intern () method, so let’s look at how it works in different JDK versions.

The realization of the JDK1.6

In JDK1.6 and earlier, the constant pool allocates memory in the permanent generation. Memory in the permanent generation and the Java heap are physically isolated. If the string already exists, a reference to the constant object in the constant pool is returned. Therefore, use the intern method carefully to avoid excessive strings in the constant pool, which may slow down performance or even cause PermGen memory overflow.

String str1 = new String("abc");
String str1Pool = str1.intern();
System.out.println(str1Pool == str1);
Copy the code

The above code will print false in JDK1.6. Let’s take a look at the memory structure:

In the code above, when the new String is the same as the memory result analyzed earlier, two objects are created in the constant pool and the heap. When str1 calls intern, the method returns the address of the object in the constant pool. At this point, str1 refers to the address of the object in the heap, and str1Pool refers to the address of the constant pool, so it is not equal.

There are also cases where string constants do not exist in the constant pool:

String str1 = new String("a") + new String("bc");
String str1Pool = str1.intern();
System.out.println(str1Pool == str1);
Copy the code

The memory structure is as follows:

In the code above, the object generated by string str1 does not exist in the constant pool, but entirely in the heap. Of course, the strings “a” and “BC” are stored in the constant pool when the object is created. When you call intern, it checks if ABC exists in the constant pool. If it does not, it copies ABC to the constant pool. Intern returns the address of the constant pool. At this point, it is obvious that str1Pool and STR1 point one to the constant pool and one to the heap address, so they are not equal.

But in JDK1.7 and beyond, things have changed.

The realization of JDK1.7

After JDK1.7, the intern method is used to query if any references in the constant pool already exist, and if so, returns the same reference from the constant pool. However, if the corresponding string is not found in the constant pool, the string is not copied to the constant pool, but instead a reference to the original string is generated in the constant pool.

Simply put, what you put into the constant pool has changed. If it is not found in the constant pool, make a copy of it and put it in the constant pool. After 1.7, copy the address reference on the heap to the constant pool.

After 1.7, the constant pool has been moved from the method area to the heap.

We will not demonstrate the existing scenarios, same as JDK1.6. Let’s look at the case where there is no corresponding string in the constant pool.

String str1 = new String("a") + new String("bc");
String str1Pool = str1.intern();
System.out.println(str1Pool == str1);
Copy the code

The memory structure changes as follows:

The initial creation of an “ABC” object is the same as in JDK1.6, where an object is created in the heap and there is no “ABC” in the constant pool.

When intern is called, instead of copying the “ABC” literal for storage, the constant pool directly stores the address of “ABC” in the heap in the constant pool, and intern returns the address of the object in the heap.

In this case, you will find that the reference addresses stored in str1 and str1Pool are “ABC” addresses in the heap. So the result of the above method execution is true.

Implementation structure of thread pools

Java uses jni to call the c++ implementation of the StringTable intern method, which is similar to the Java implementation of HashMap, but cannot be automatically expanded. The default size is 1009.

That is, the String constant pool for String is a fixed size Hashtable. If there are too many strings in the constant pool, it can cause Hash collisions, resulting in long lists, which can lead to performance degradation when string.intern is called.

In JDK1.6, StringTable has a fixed length of 1009. In JDK1.7, the length of a StringTable can be specified with a single argument:

-XX:StringTableSize=99991
Copy the code

Therefore, be careful when using the INTERN method. So, what scenarios are appropriate for using intern?

This is when the corresponding string is reused a lot. For example, the Nacos code we talked about in the beginning, which is the name of the service that basically does not change and is used repeatedly, would be appropriate in the constant pool.

At the same time, it is important to know that although intern can reduce memory usage, it will increase the application time due to the additional operation. But this is a negligible increase compared to the JVM’s garbage collection time.

conclusion

This article was written purely from reading a line of code in the open source framework, but it is interesting to think about why it is used this way and explore the principles and knowledge behind it.

The interview series

  • Interview questions: Talk about TCP sticky, unpack, and Solutions
  • Interview question: Why does overriding equals usually override hashCode?
  • Interviewer: How to find the longest string in a string without repetition?
  • Don’t Understand Java generics? Just use this article to make sure you have a good interview answer.
  • Interview Question: 8 Ways to Invert a string. What can you Think of?

Program new horizon

\

The public account “program new vision”, a platform for simultaneous improvement of soft power and hard technology, provides massive information

\