Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why JVM is not "seeing" duplicate String value in String Pool memory?

Possibly this is a duplicate, but couldn't find the explanation I needed. Can someone explain me this.

If I'm correct:

String s1 = "a";
String s2 = "a";

Both s1 and s2 will point to the same address in String pool and there will be only one object with value "a".

Now, if I do this:

String s1 = "a"; //line A
s1 = s1.concat("b"); //line B; I don't understand what's happening here in terms of references
String s2 = "ab";//line C
System.out.println(s1 == s2); //false

Why do I get false?

My way of seeing this (probably wrong), goes like this:

after line A -> object is created (with value a) in String pool, referenced by s1; after line B -> object with value b is created in String pool (with no reference), then new object with value ab is created in String pool (referenced by existing s1) after line C -> (this is probably I'm wrong) Since existing object with value ab (referenced by s1) is created using concat() (or +), JVM will not reuse this object to be pointed by reference s2, it will rather just create new object in String pool with value ab pointed by reference s2;

Where am I wrong?

like image 408
Wrapper Avatar asked Dec 13 '22 08:12

Wrapper


1 Answers

TL;DR - the point of your confusion is the Java memory model for Strings, namely the Heap and String Constant Pool areas of the memory.


Deep Dive into String memory model

Design Motivation

In Java, String is probably the most heavily used object. Because of this, Java maintains String objects with a special memory design strategy, holding them either in the Heap, in the isolated subset of the heap called String Constant Pool, or in both.

String Constant Pool is a special space in the Heap memory, which holds String objects of the unique "literal value"s. Anytime you create a String with its literal value, JVM first checks if the object of the same value is available in the String pool, and if it is, reference to the same object is returned, if it doesn't - the new object is allocated in the String Constant Pool, and the same happens for all other String literal creations again and again.

Reason, why having the Constant Pool is a good idea, is the semantics of this phrase itself - because it stores the constant and immutable String objects, and as you see, this is a great idea for the occasions when you might be creating many String objects with the same literal content - in all those cases, only one object for one "literal value" will be referenced each time and no newer objects will be created for the existing String literal object.

Note, that this is only possible because, String is immutable by definition. Also, note, that a pool of strings, which initially is empty, is maintained privately by the class String.

Where does Java place String objects?

Now this is where things get interesting. Important point to bear in mind, is that whenever you create String object with a new String() instruction, you force Java to allocate the new object into Heap; however, if you create a String object with the "string literal", it gets allocated in String Constant Pool. As we've said, the String Constant Pool exists mainly to reduce memory usage and improve the re-use of existing String objects in the memory.

So, if you'll write:

String s1 = "a";
String s2 = "a";
String s3 = new String("a");
  1. String object will be created into String Constant Pool and reference to that object will be stored into variable s1;
  2. String Constant Pool will be looked-up, and because of there is an object with the same literal value ("a") found in the pool, reference to the same object will be returned;
  3. String object will be explicitly created on the Heap area and the reference will be returned and stored into variable s3.

Internig Strings

If you wish to move the String object, created with new operator, into the String Constant Pool, you can invoke "your_string_text".intern(); method, and one of two will happen:

  1. if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool will be returned;
  2. otherwise, this String object will be added to the pool and a reference to this String object will be returned.

What happens in your code?

String s1 = "a";
String s2 = "a";

Both s1 and s2 will point to the same address in String pool and there will be only one object with value "a".

True. Initially, String object will be created and it will be placed into String Constant Pool. After that, as there is already String with value "a", no new object will be created for s2 and reference stored in s1 will be similarly stored into s2.

Now, let's finally have a look at your question:

String s1 = "a"; //allocated in the String Constant Pool
s1 = s1.concat("b"); //contact() returns a new String object, allocated in the Heap
String s2 = "ab";//"ab" still does NOT exist in the String Constant Pool, and it gets allocated there
System.out.println(s1 == s2); //returns false, because one object is in the Heap, and another is in the String Constant Pool, and as there already exists the object in the pool, with the same value, existing object will be returned by `intern()`.

If you will, however, execute

System.out.println(s1.intern() == s2);

this will return true, and I hope, by now, you understand - why. Because intern() will move the object referenced via s1 from Heap to the String Constant Pool.

like image 74
Giorgi Tsiklauri Avatar answered May 10 '23 00:05

Giorgi Tsiklauri