I have known that JVM maintains a string literal pool to increase performance and maintain JVM memory and learned that string literal is maintained in the string pool. But I want to clarify something related to the string pool and string object created on the heap.
Please correct me if my explanation is wrong.
String s = "abc";
If the above line is executed, "abc" string literal is added to the string pool if it does not exist in the pool. And string object is created on the heap and a reference s will point to the literal in the pool.
Questions:
Does this code create string object on the heap every time it is executed?
Does string literal pool maintain only string literals or does it maintain string object as well?
When does JVM decide that it needs to add string literal to the string pool? does it decide in the compile time or runtime?
I am not sure where exactly string object is created if it points to a string literal in the pool.
Thanks.
There is no "literal pool". Interned Strings are just normal heap objects. They may end up in the PermGen, but even then, they could eventually be garbage-collected.
The class file has a constant pool, which contains the String literals used in the class. When the class is loaded, String objects are created from that data, which is probably very similar to what String#intern does.
Does this code create string object on the heap every time it is executed?
No. There will be one String object that is being reused. It has been created when the class was loaded.
Does string literal pool maintain only string literals or does it maintain string object as well?
You can intern Strings as well. I assume that they are treated more or less the same.
When does JVM decide that it needs to add string literal to the string pool? does it decide in the compile time or runtime?
Literals are always "pooled". Other Strings need to have "intern" called on them. So in a way, the decision is made at compile-time.
Quoting documentation for String.intern()(emphasis mine)
All literal strings and string-valued constant expressions are
interned. String literals are defined in ยง3.10.5 of the Java Language
Specification
A pool of strings, initially empty, is maintained privately by the
class String.
When the intern method is invoked, 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 is returned. Otherwise, this
String object is added to the pool and a reference to this String
object is returned.
Thus,
Does this code create string object on the heap every time it is
executed?
Only one object is created for each unique interned string. All references share this immutable object.
Does string literal pool maintain only string literals or does it maintain string object as well?
There are no 'Literal Objects'. Literal string expressions when converted, are stored as regular String objects.Also, the pool contains all interned string objects. Both implicit (by using a string literal expression) and explicit (by calling .intern() on a String object).
When does JVM decide that it needs to add string literal to the string
pool? does it decide in the compile time or runtime?
I'm not sure.
I think there's something fundamental you're missing: the interned strings pool only contains String objects. Literals are not some sort of special object; at runtime they are just another String object.
Plus you can intern any String you want using String.intern(); it doesn't have to originate from a literal.
So regarding your questions:
No, there will be one String object allocated when the class is loaded.
It doesn't maintain any literals but rather String objects that were interned. Usually, those come from literals but in reality it could be any compile-time constant expression (String constant = "abc" + "def" would result in one String object "abcdef" at runtime).
They are compiled into the class file. So they are decided at compile time but obviously the objects themselves are created at runtime.
Does this code create string object on the heap every time it is executed?
Nope. Once created in the literal pool. The same referred again and again.
Does string literal pool maintain only string literals or does it maintain string object as well?
All are objects only, but objects created via assignment are put in pool where as the one created via new operator are put on heap.
When does JVM decide that it needs to add string literal to the string pool? does it decide in the compile time or runtime?
Whenever JVM comes across an expressions like
String str="Hello"; (string literal) or
String str="Hel" + "lo"; (string constant expression).
and the resultant string (str in this case) is not the pool, then in all such cases it adds the new string in the pool. This off course happens at runtime.
Check out this link.
Related
In Java, when an object has got no live reference, it is eligible for garbage collection. Now in case of a string, this is not the case because the string will go into the string pool and JVM will keep the object alive for re-use.
So that means a string once created will 'never' be garbage collected?
Now in case of a string, this is not the case because string will go into the string pool and JVM will keep the object alive for reuse. So that means a string once created will 'never' be garbage collected?
First, it is only string literals (see notes) that get automatically interned / added to the string pool. String objects that are created by an application at runtime are not interned ... unless your application explicitly calls String.intern().
Second, in fact the rules for garbage collecting objects in the string pool are the same as for other String objects: indeed all objects. They will be garbage collected if the GC finds them to be unreachable.
In practice, the String objects that correspond to string literals typically do not become candidates for garbage collection. This is because there is an implicit reference to the String object in the code of every method that uses the literal. This means that the String is reachable for as long as the method could be executed.
However, this is not always the case. If a string literal was defined in a class that was dynamically loaded (e.g. using Class.forName(...)), then it is possible to arrange that the class is unloaded. If that happens, then the String object corresponding to the literal may then be unreachable, and may ultimately be GC'ed.
See also: When and how are classes garbage collected in Java?
Notes:
A string literal (JLS 3.10.5) is a string that appears in Java source code; e.g.
"abc" // string literal
new String(...) // not a string literal
A string produced by evaluation of (compile-time) constant expression (JLS 15.28) may also be interned.
"abc" + 123 // this is a constant expression
Strictly speaking, not all String literals are interned:
If a String literal only appears in the source code as a sub-expression of a constant expression, then the literal may not appear in the ".class" file in any form. Such a literal won't be interned because it won't exist at runtime.
In Java 9+, string concatenations involving literals and values that are not compile time constants may be handled differently. Now, at the option of the bytecode compiler, a string concatenation like the following:
int x = 42; // not a compile time constant
String s = "prefix " + x + " suffix";
may result in a string constant like the following being interned:
"prefix \1 suffix"
At runtime, the above string constant is used as the "recipe" for generating a dynamic concatenation method. The original string literals (i.e. "prefix " and " suffix") would not turn into interned string objects.
Kudos to #Holger for pointing this out. More details are in JEP 280 and the javadoc for StringConcatFactory.
Prior to Java 7, the string pool was in PermGen. For some versions of Java, garbage collection of PermGen was not enabled by default if you selected the CMS collector. But CMS was never the default collector AND there was a flag to enable PermGen collection by CMS. (And nobody should be developing code for Java 6 and earlier anymore.)
You are correct; strings in the intern pool will never be GC'd.
However, most strings on not interned.
String literals are interned, and strings passed to String.intern() are interned, but all other strings are not interned and can be GC'd normally.
String objects which are in the string pool will not be garbage collected. Other String objects will be garbage collected if you don't have reference to it in your program execution.
You may ask which string objects goes to string pool.Objects in the string pool are either:
Compile time literals (e.g.String s1 = "123";)
Interned String objects in the runtime (e.g. String s2 = new String("test").intern();)
Both s1 and s2 reference a string object in the string pool.
Any objects which are created at run time and not interned will act as a normal object and reside in heap memory. These objects can be garbage collected.
An example of this would be: String s3 = s1 + s2;
Here, s3 references a string object which resides in heap memory alongside other objects (not in the String pool).
Before Java 7 the string pool resided in Permanent Generation space. So string literals were never garbage collected (which also led to out of memory issues many a times)
After Java 7, string pool is placed in heap space, which is garbage collected by the JVM. It also reduces the chances of getting Out of memory issues in JVM.
If jvm creates string pool for memory optimization, then why it creates new Object each time we create string using new keyword even though it exists in string pool?
... why does Java create new Object each time we create a string using the new keyword even though it exists in string pool?
Because you explicitly told it to! The new operator always creates a new object. JLS 15.9.4 says:
"The value of a class instance creation expression is a reference to the newly created object of the specified class. Every time the expression is evaluated, a fresh object is created."
For the record, it is nearly always a mistake to call new String(String) ... but in obscure cases it might be useful. It is conceivable that you might want a string for which equals returns true and == gives false. Calling new String(String) will give you that.
For older versions of Java, the substring, trim and possibly other String methods would give you a string that shared backing storage with the original. Under certain circumstances, this could result in a memory leak. Calling new String(str.trim()) for example would prevent that memory leak, at the cost of creating a fresh copy of the trimmed string. The String(String) constructor guarantees to allocate a fresh backing array as well as giving you a new String object.
This behavior of substring and trim changed in Java 7.
To give primitive style of declaration and for performance designers introduced String literals.
But when you use new keyword, then you are explicitly creating objects on heap not in constant pool.
When the objects created on heap, there is no way to share that memory with each other and they become completely strangers unlike in constant pool.
To break this barrier between heap and constant pool String interning will help you out.
string interning is a method of storing only one copy of each distinct string value, which must be immutable
Remember that constant pool also a small part of heap with some additional benefits where sharing of memory is available.
When you write
String str = new String("mystring");
then it creates a string object in heap just like other object which you create. The string literal "mystring" is stored in the string constant pool.
From the Javadocs:
A pool of strings, initially empty, is maintained privately by the
class String.
When the intern method is invoked, 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 is returned. Otherwise, this
String object is added to the pool and a reference to this String
object is returned.
It follows that for any two strings s and t, s.intern() == t.intern()
is true if and only if s.equals(t) is true.
To take advantage of string pooling you need to use String#intern instead of new.
Following object will be stored in String pool :
String s = "hello";
And following object will be stored in Heap (not in string pool):
String s = new String ("hello")
To enforce garbage collection!. If you need some String just one time, then there is no point in keeping it in memory (for almost forever. Which is the case with Strings in constant pool). Strings which are not in the constants pool can be GCed like any other object. So, you should only keep frequently used Strings in the constants pool (by using literals or interning them).
Strings created in the form of String literals (String s = "string";) are stored in string pool, but Strings created by invoking String constructor using new (String s = new String("string");, are not stored in string pool.
In Java, when an object has got no live reference, it is eligible for garbage collection. Now in case of a string, this is not the case because the string will go into the string pool and JVM will keep the object alive for re-use.
So that means a string once created will 'never' be garbage collected?
Now in case of a string, this is not the case because string will go into the string pool and JVM will keep the object alive for reuse. So that means a string once created will 'never' be garbage collected?
First, it is only string literals (see notes) that get automatically interned / added to the string pool. String objects that are created by an application at runtime are not interned ... unless your application explicitly calls String.intern().
Second, in fact the rules for garbage collecting objects in the string pool are the same as for other String objects: indeed all objects. They will be garbage collected if the GC finds them to be unreachable.
In practice, the String objects that correspond to string literals typically do not become candidates for garbage collection. This is because there is an implicit reference to the String object in the code of every method that uses the literal. This means that the String is reachable for as long as the method could be executed.
However, this is not always the case. If a string literal was defined in a class that was dynamically loaded (e.g. using Class.forName(...)), then it is possible to arrange that the class is unloaded. If that happens, then the String object corresponding to the literal may then be unreachable, and may ultimately be GC'ed.
See also: When and how are classes garbage collected in Java?
Notes:
A string literal (JLS 3.10.5) is a string that appears in Java source code; e.g.
"abc" // string literal
new String(...) // not a string literal
A string produced by evaluation of (compile-time) constant expression (JLS 15.28) may also be interned.
"abc" + 123 // this is a constant expression
Strictly speaking, not all String literals are interned:
If a String literal only appears in the source code as a sub-expression of a constant expression, then the literal may not appear in the ".class" file in any form. Such a literal won't be interned because it won't exist at runtime.
In Java 9+, string concatenations involving literals and values that are not compile time constants may be handled differently. Now, at the option of the bytecode compiler, a string concatenation like the following:
int x = 42; // not a compile time constant
String s = "prefix " + x + " suffix";
may result in a string constant like the following being interned:
"prefix \1 suffix"
At runtime, the above string constant is used as the "recipe" for generating a dynamic concatenation method. The original string literals (i.e. "prefix " and " suffix") would not turn into interned string objects.
Kudos to #Holger for pointing this out. More details are in JEP 280 and the javadoc for StringConcatFactory.
Prior to Java 7, the string pool was in PermGen. For some versions of Java, garbage collection of PermGen was not enabled by default if you selected the CMS collector. But CMS was never the default collector AND there was a flag to enable PermGen collection by CMS. (And nobody should be developing code for Java 6 and earlier anymore.)
You are correct; strings in the intern pool will never be GC'd.
However, most strings on not interned.
String literals are interned, and strings passed to String.intern() are interned, but all other strings are not interned and can be GC'd normally.
String objects which are in the string pool will not be garbage collected. Other String objects will be garbage collected if you don't have reference to it in your program execution.
You may ask which string objects goes to string pool.Objects in the string pool are either:
Compile time literals (e.g.String s1 = "123";)
Interned String objects in the runtime (e.g. String s2 = new String("test").intern();)
Both s1 and s2 reference a string object in the string pool.
Any objects which are created at run time and not interned will act as a normal object and reside in heap memory. These objects can be garbage collected.
An example of this would be: String s3 = s1 + s2;
Here, s3 references a string object which resides in heap memory alongside other objects (not in the String pool).
Before Java 7 the string pool resided in Permanent Generation space. So string literals were never garbage collected (which also led to out of memory issues many a times)
After Java 7, string pool is placed in heap space, which is garbage collected by the JVM. It also reduces the chances of getting Out of memory issues in JVM.
String str1="JAVA";
String str2="JAVA";
String str3=new String("JAVA");
String str4=new String("JAVA").intern();
2 objects will be created. str1 and str2 refer to same object because of String literal pool concept and str3 points to new object because using new operator and str4 points to the same object points by str1 and str2 because intern() method checks into string pool for string having same value.
str1=str2=str3=str4=null;
One object will be eligible for GC. That is the object created through String str3=new String("JAVA"). The first String object is always accessible through reference stored in string literal pool.
Is my explanation correct?
Total Number of String objects created in the process?
Three: The one in the intern pool created via the literal and the two you create via new String.
One object will be eligible for GC.
I count two, and possibly even all three under very special circumstances:
The one you created in this line:
String str3=new String("JAVA");
(since you later set str3 to null).
The one you created temporarily in this line:
String str4=new String("JAVA").intern();
That line creates a new String object, calls intern on it, and then saves a reference to the string from the pool. So in theory, it creates a String object that is immediately available for GC. (The JVM may be smart enough not to do that, but that's the theory.)
Possibly, eventually, under the right conditions, even the string in the intern pool. Contrary to popular belief, strings in the intern pool are available for garbage collection as we can see from the answer to this other question. Just because they're in the permgen (unless you're using Oracle's JVM 7 or later) that doesn't mean they're not GC'd, since the permgen is GC'd too. So the question becomes: When or how is a string literal used in code no longer referenced? I don't know the answer, but I think a reasonable assumption would be: When and if the class using it is unloaded from memory. According to this other answer, that can only happen if both the class and its classloader are unloaded (and may not happen even then). If the class was loaded by the system classloader (the normal case), then presumably it's never unloaded.
So almost certainly just two (#1 and #2 above), but it was fun looking into #3 as well.
java docs says:
A pool of strings, initially empty, is maintained privately by the
class String.
1) Is it a pool of string literals or references to these string literals? on net some articles refer it as pool of strings literals while other refer it as pool of references so i got confused.
2) Is string pool created per class basis or per JVM basis?
3)Is there any reference where i can find details of string pool, its implementation etc.?
1) Is it a pool of string literals or references to these string literals? on net some articles refer it as pool of strings literals while other refer it as pool of references so i got confused.
It is the same thing. You can't have a String object without a reference, or vice-versa.
And, as Peter Lawrey puts it: "In Java, an Object is inside the heap. Nowhere else. The only thing you can have inside something else, an object, an array, a collection or the stack, is a reference to that object."
2) Is string pool created per class basis or per JVM basis?
There is one String pool per JVM ... unless you are using some exotic JVM where they've decided to implement it differently. (The spec doesn't say that there has to be one string pool for the JVM, but that's generally the most effective way to do it.)
3)Is there any reference where i can find details of string pool, its implementation etc.?
You can download the complete source code of OpenJDK 6 or 7. The spring pool is implemented in native code ... so you'll be reading C++.
Is it a pool of string literals or references to these string literals?.
well, obviously it is pool of string literals. suppose you write,
String str= "a learner";
It will search in String pool by equals() method whether the same string is there in string pool or not.If it is there in Pool, that String object is returned, otherwise it is stored in String Pool and a reference to newly added string is returned.
So , it is pool of String objects, on which equals() method is called whenever you type a new string literal.
Is string pool created per class basis or per JVM basis?
There can be only one class of String in JVM because String class is final. So there is no question of more than one String class per JVM. Ultimately it comes out to be only one String Pool per JVM.
It's called String interning.
It is a pool of String literals
Interning is done on a JVM basis
The JDK source for String has all the code in there