Questions about Java's String pool [duplicate]
Asked Answered
T

7

72

Consider this code:

String first = "abc"; 
String second = new String("abc");

When using the new keyword, Java will create the abc String again right? Will this be stored on the regular heap or the String pool? How many Strings will end in the String pool?

Thong answered 10/12, 2009 at 15:51 Comment(2)
@dmindreader: I'm not sure what you want to use this for... but it reminds me of something I read before and posted as an answer to another SO question. Please read my answer to the other question as it emphasizes that relying on these implementation details can be fragile: #1111796Mentholated
refer this #3052942Saenz
B
97

If you use the new keyword, a new String object will be created. Note that objects are always on the heap - the string pool is not a separate memory area that is separate from the heap.

The string pool is like a cache. If you do this:

String s = "abc";
String p = "abc";

then the Java compiler is smart enough to make just one String object, and s and p will both be referring to that same String object. If you do this:

String s = new String("abc");

then there will be one String object in the pool, the one that represents the literal "abc", and there will be a separate String object, not in the pool, that contains a copy of the content of the pooled object. Since String is immutable in Java, you're not gaining anything by doing this; calling new String("literal") never makes sense in Java and is unnecessarily inefficient.

Note that you can call intern() on a String object. This will put the String object in the pool if it is not already there, and return the reference to the pooled string. (If it was already in the pool, it just returns a reference to the object that was already there). See the API documentation for that method for more info.

See also String interning (Wikipedia).

Besotted answered 10/12, 2009 at 15:52 Comment(13)
Presumably this is based on the Fly-weight design pattern.Slavism
@Wim: Yes, this is essentially the flyweight pattern.Besotted
the intern() pool is always on heap; I suppose that the question is asking about the class constants poolDuren
beware of running out of permgen space. Using your own set to intern strings avoids this.Larcenous
you mean by the string pool, the constant pool, right?Copter
@bmargulies: Yes, it is a bad idea to just intern() strings without thinking, it will create a memory leak. @HH: The class constants pool is not the same thing as the string pool.Besotted
@Jesper: I want something to be clear. new String("literal") doesn't make sense as you say, but I hope you are not suggesting that calling "new String(someString)" doesn't make sense and is unnecessarily inefficient. Imagine you have String s = "someExtremelyExtremelyLongStringLiteral";. Then you will want to use String sub = new String(s.substring(0,1)); instead of String sub = s.substring(0,1); as the latter version can waste memory. The reason is that when the reference s goes away, there will still be a reference sub pointing to the huge underlying char[] so it can't be GC'edMentholated
@Jesper: I told dmindreader to look at this answer I posted on SO a while ago, and I thought you might be interested in it since you talked about intern(). It points out that string interning is a fragile thing to rely on as programmer and really is an implementation detail of the JVM. #1111796Mentholated
@Tom: I understand, what I meant was that calling new String() with a string literal is never necessary.Besotted
@Mentholated That implementation detail was changed in Java 7 update 6. Now, when you invoke "someExtremelyExtremelyLongStringLiteral".substring(0, 1), a new, 1-character char[] is allocated, and the substring is completely independent of the original literal. There is no longer any char[] sharing between String, StringBuilder, etc. So, moving forward, there really is never a good reason to use new String(String)Leucite
How can the compiler maintain the String Pool as it does not have access to the Run Time Memory areas (Heap/Method Area). It should be the task of JVM.Remittance
I heard that before Java 7, string pool is on perm gen and now upon Java 7 it is on heap, right? What I don't understand is that, when I create with new, they are always automatically interned?Macdonell
@Macdonell When you create a String object with new, it is not automatically interned. Only string literals (strings between quotes in your source code) are automatically interned.Besotted
D
12

In bytecode, the first assignment is:

  Code:
   0:   ldc     #2; //String abc
   2:   astore_1

whereas the second is:

   3:   new     #3; //class java/lang/String
   6:   dup
   7:   ldc     #2; //String abc
   9:   invokespecial   #4; //Method java/lang/String."":(Ljava/lang/String;)V

So the first is in the pool (at position #2) whereas the second will be stored in the heap.

EDIT

Since the CONSTANT_String_info store the index as U2 (16 bits, unsigned) the pool can contain at max 2**16 = 65535 references. In the case you care here more limits of the JVM.

Duren answered 10/12, 2009 at 15:53 Comment(3)
Looking at the bytecode is a good (and overlooked) way to find out what exactly a program is doing.Besotted
How do you look at the bytecode? What did you use to access it?Thong
javap, an utility distributed in the jdk of sun java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javap.htmlDuren
A
7

Each time your code create a string literal

for example:

String str="Hello"; (string literal) 

the JVM checks the string literal pool first. If the string already exists in the pool, a reference to the pooled instance returns. If the string does not exist in the pool, a new String object instantiates, then is placed in the pool. Java can make this optimization since strings are immutable and can be shared without fear of data corruption

Alveolus answered 10/12, 2009 at 17:6 Comment(2)
Isn't this check performed by the java compiler, rather than the JVM?Razee
This answer to the same question states that's correct.Sadoc
C
3
String strObject = new String("Java");

and

String strLiteral = "Java";

Both expression gives you String object, but there is subtle difference between them. When you create String object using new() operator, it always create a new object in heap memory. On the other hand, if you create object using String literal syntax e.g. "Java", it may return an existing object from String pool (a cache of String object in Perm gen space, which is now moved to heap space in recent Java release), if it's already exists.

Conk answered 25/5, 2015 at 11:21 Comment(2)
you have taken avoe text from (Difference between String literal and New String object in Java)[java67.blogspot.com/2014/08/… ] its good to mention reference url from which you have taken detailsDemarcation
It will return an object from the string pool if it's a literal. No 'may' about it.Cozmo
D
2

The only time you should use new String(foo) is when you want to break ==, which is an odd case, or when foo is a substring of a much larger string that has a limited lifetime, such as

String mystring;
{
   String source = getSomeHeinouslyLargeString();
   mystring = new String(source.substring(1,3));
}
Dendritic answered 12/12, 2009 at 5:44 Comment(0)
T
1

Though late, may be useful for someone still come across this:

String first = "abc";
//One instance object in pool created. Instance variable “first” refers/points to pooled object

String second = new String("abc");    
//One instance object in heap created. Object in pool creation step will be skipped on account of first statement.

So in total 2 instance objects will be created. One in pool and other in heap

Detailed Explanation

String first = "abc";

Here a string object with content "abc" created in pool. The instance variable “first” will point to pool object with content “abc”.

String second = new String("abc");

Here another string object with content "abc" will be created in heap. The instance variable “second” will point to heap object with content “abc”. A string object with content "abc" creation in pool will be skipped on account of 1st statement. Reason below.

Reasons

If assumed prior statement (String first = "abc";) is not there with same content, then generally with “new” keyword, 2 string objects will be created one in heap (outside pool) and the other in pool(a subset area of heap). Also the instance variable "second" should point to heap object only, irrespective of whether the objects is in pool or not.

Now on account of the presence of prior statement (String first = "abc";) with same content as in new String("abc"), only one object (with content "abc") is retained in pool. So on account of 1st statement, the second statement will have only 1 object created instead of 2 and that object is in heap. Pool object creation will be skipped.

//Additional Test on the concept
System.out.println(first==second);  //returns false. Because first points to pool object while second points to heap object. And both objects are different (on account of different memory locations).

second = second.intern();           //After interning, second now points to pool object. Note: intern is used so that reference variable points to pool area object and not heap object. Clearly it is applicable when we use new keyword.

System.out.println(first==second);  //returns true. Because now both first and second objects now points to same pool object.
Thick answered 14/12, 2017 at 7:36 Comment(1)
If String s = new String("first"); is first statement, it would create 2 objects (one in heap and one in string pool), right? But why does it create object in pool when it would never compare itself with pooled objects?Clubby
J
0
String first = "abc"; 
String second = new String("abc");

In first case there is only one object will create in Pool. In second case two object will create one in pool (if this is not existing previously in Pool) and one in heap.

When you are passing any value with double quote ex: "abc" you are creating a object in pool and passing it to the string constructor for creating a new object with the same value in heap.

If you saw the string constructor you can see that it accept a string. What is that string? Before creation what is that string object. It's nothing but an object stored in String Constant pool.

Jeffers answered 22/2, 2018 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.