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.
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.
String s = "hello";
String literals have references in String Literal Pool and are not eligible of garbage collection, ever. So, after above line even if I say:
s=null;
String object "hello" will still be in heap as I understand. Source: https://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html
Does same holds true for strings inside String array? Suppose we have
String[] arr = {"one","two","three"};
arr=null;
Will the 3 string objects still be on heap referenced from pool? or they will be eligible for garbage collection along with array object.
String literals have references in String Literal Pool and are not eligible of garbage collection, ever.
Actually, that is not strictly correct ... see below.
Will the 3 string objects still be on heap referenced from pool? or they will be eligible for garbage collection along with array object.
They will not be referenced "from the pool". The references in the pool are (in effect) weak references.
They will not be eligible for garbage collection.
What is actually going to happen is that the String objects (in the string pool) that correspond to string literals in the source code will be referenced by the code that uses the literals; i.e. there are hidden references in hidden objects that the JVM knows about. These references are what the JVM uses when you (for example) assign the string literal to something ...
It is those hidden references that mean the weak references in the pool don't break, and the corresponding String objects don't get garbage collected.
Now, if the code that defines the literals was dynamically loaded, and the application manages to unload the code, then the String objects may become unreachable. If that happens, they will eventually be garbage collected,
After exploring java's string internals I've grown confused on what is referred to as the "perm space." My understanding initially of it was that it held String literals as well as class meta data as explained in this question.
I've also read about the String.intern() method and that it places Strings into the String Pool returning a reference to unique instance of it. It is my understanding that this is the same string pool holding String literals that exists in the JVM's perm-space. It didn't seem possible to me that the "perm-space" could be modifiable, (it is permanent after all, yes?). But Then I found this question where the top voted comment by EJP on the accepted answer explains that
Intern'd strings have been GC-able for quite some years now.
Implying that the GC runs on the perm-space which doesn't seem very permanent. How does this reconcile? Does the GC check everything in the perm-space? Does the GC check everything in the string pool including string literals from the source? Is there a second string pool for intern'd strings? Does the GC know only to look over intern'd strings when collecting? Or is this comment mistaken and intern'ing a string prevents it from ever being GC'd (which I hope is not the case)?
String literals are interned. As of Java 7, the HotSpot JVM puts interned Strings in the heap, not permgen.
Prior to java 7, hotspot put interned Strings in permgen. However, interned Strings in permgen were garbage collected. Apparently, Class objects in permgen are also collectable, so everything in permgen is collectable, though permgen collection might not be enabled by default in some old JVMs.
String literals, being interned, would be a reference held by the declaring Class object to the String object in the intern pool. So the interned literal String would only be collected if the Class object that referred to it were also collected.
I am reading about Garbage collection and i am getting confusing search results when i search for String literal garbage collections.
I need clarification on following points:
If a string is defined as literal at compile time [e.g: String str = "java"] then will it be garbage collected?
If use intern method [e.g: String str = new String("java").intern()] then will it be garbage collected? Also will it be treated differently from String literal in point 1.
Some places it is mentioned that literals will be garbage collected only when String class will be unloaded? Does it make sense because I don't think String class will ever be unloaded.
If a string is defined as literal at compile time [e.g: String str = "java";] then will it be garbage collected?
Probably not. The code objects will contain one or more references to the String objects that represent the literals. So as long as the code objects are reachable, the String objects will be to.
It is possible for code objects to become unreachable, but only if they were dynamically loaded ... and their classloader is destroyed.
If I use the intern method [e.g: String str = new String("java").intern()] then will it be garbage collected?
The object returned by the intern call will be the same object that represents the "java" string literal. (The "java" literal is interned at class loading time. When you then intern the newly constructed String object in your code snippet, it will lookup and return the previously interned "java" string.)
However, interned strings that are not identical with string literals can be garbage collected once they become unreachable. The PermGen space is garbage collected on all recent HotSpot JVMs. (Prior to Java 8 ... which drops PermGen entirely.)
Also will it be treated differently from string literal in point 1.
No ... because it is the same object as the string literal.
And indeed, once you understand what is going on, it is clear that string literals are not treated specially either. It is just an application of the "reachability" rule ...
Some places it is mentioned that literals will be garbage collected only when String class will be unloaded? Does it make sense because I don't think the String class will ever be unloaded.
You are right. It doesn't make sense. The sources that said that are incorrect. (It would be helpful if you posted a URL so that we can read what they are saying for ourselves ...)
Under normal circumstances, string literals and classes are all allocated into the JVM's permanent generation ("PermGen"), and usually won't ever be collected. Strings that are interned (e.g. mystring.intern()) are stored in a memory pool owned by the String class in permgen, and it was once the case that aggressive interning could cause a space leak because the string pool itself held a reference to every string, even if no other references existed. Apparently this is no longer true, at least as of JDK 1.6 (see, e.g., here).
For more on permgen, this is a decent overview of the topic. (Note: that link goes to a blog associated with a product. I don't have any association with the blog, the company, or the product, but the blog entry is useful and doesn't have much to do with the product.)
The literal string will remain in memory as long as the program is in memory.
str will be garbage collected, but the literal it is created from will not.
That makes perfect sense, since the string class is unloaded when the program is unloaded.
intern() method checks the availability of the object in String pool. If the object/literal is available then reference of it will be returned. If the literal is not there in the pool then object is loaded in the perm area (String pool) and then reference to it will be return. We have to use intern() method judiciously.
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.