Immutability of String in JAVA - java

Consider the code :
public class Stringer {
public static void main(String[] args) {
String s1 = "SomeLine";
System.out.println(s1); // prints SomeLine
s1 = "AnotherLine";
System.out.println(s1); // prints AnotherLine
}
}
When I change s1 from SomeLine to AnotherLine , since Strings are Immutable , does this mean that SomeLine is lost and is eligible for GC ?
Much appreciated

When I change s1 from SomeLine to AnotherLine, since Strings are
Immutable, does this mean that SomeLine is lost and is eligible for
GC?
The fact that String is immutable is irrelevant to your question. The fact that you are reassigning the variable and therefore losing the other reference is what determines if the object is a candidate for GC or not.
To answer the question, it would be if it wasn't a String literal.
Moreover, a string literal always refers to the same instance of class
String. This is because string literals - or, more generally, strings
that are the values of constant expressions (§15.28) - are "interned"
so as to share unique instances, using the method String.intern.
That String object won't be garbage collected because the ClassLoader and the corresponding class have a reference to it.
Related reading:
What is the difference between "text" and new String("text")?

Yes you're right, it does become eligible for garbage collection. This is because you are no longer referencing the original string with your variable.
Here is a related question on SO:
Aren't String objects in Java immutable?

It is not that trivial when talking about Strings in Java. Even if the String is interned it can still be garbage collected. In java 6, even if it is allocated in the permgen, it can be garbage collected, in Java 7 they are allocated on the Heap and are still eligible for GC.
Usually interned Strings are not eligible for garbage collection because the class has a reference to it. But what if that class was loaded dynamically (Class.forName)? It could easily be the case when that Class could be unloaded, thus an interned string could be reclaimed by GC.
See an example here that shows that interned strings could be garbage collected.

Related

Are string objects and their literals garbage collected?

I have some questions revolving around the garbage collection of string objects and literals and the string pool.
Setup
Looking at a code snippet, such as:
// (I am using this constructor on purpose)
String text = new String("hello");
we create two string objects:
"hello" creates one and puts it into the string pool
new String(...) creates another, stored on the heap
Garbage collection
Now, if text falls out of scope and nobody references them anymore, it can be garbage collected, right?
But what about the literal in the pool? If it is not referenced by anyone anymore, can it be garbage collected as well? If not, why?
When we create a String via the new operator, the Java compiler will create a new object and store it in the heap space reserved for the JVM.
To be more specific, it will NOT be in the String Pool, which is a specialized part of the (heap) memory.
String text = new String("hello");
As soon as there is no more reference to the object it is eligible for GC.
In contrast, the following would be stored in the string pool:
String a = "hello";
When we call a similar line again:
String b = "hello";
The same object will be used from the String Pool, and it will never be eligible for GC.
As to why:
To reduce the memory needed to hold all the String literals (and the
interned Strings), since these literals have a good chance of being
used many times over.
The specification does not mandate a behavior. All it requires, is that all string literals (and string-typed compile-time constants in general) expressing the same string, evaluate to the same object at runtime.
JLS §3.10.5:
At run time, a string literal is a reference to an instance of class String (§4.3.3) that denotes the string represented by the string literal.
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.29) - are "interned" so as to share unique instances, as if by execution of the method String.intern (§12.5).
Its also repeated in JLS §15.29:
Constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern
This implies that each Java implementation maintains a pool at runtime which can be used to look up the canonical instance of the string. But the pool doesn’t have to hinder garbage collection. If no other reference to the object exists, the string instance could be garbage collected, as the fact that a new string instance has to be constructed when necessary, is unobservable.
Note that when you add strings to the pool manually, by invoking intern(), the string instances may indeed get garbage collected when otherwise being unreachable.
But in practice, the common implementations, like the HotSpot JVM associate a reference from the code location to the string instance after the first execution, so the object is referenced by the code containing the string literal or compile-time constant. So, the object associated with the string literal can only get garbage collected, when the class itself gets garbage collected. This is only possible when its defining class loader and in turn, all other classes defined by this loader are unreachable too.
For the application class loader, this is impossible. Class unloading can only happen for additional class loader created at runtime. Then, the string instances created for compile-time constants within classes loaded by this class loader may get garbage collected, if not matching constants in other code.

Confusion on string immutability

I have following code:-
public class StaticImplementer {
private static String str= "ABC";
public static void main(String args[]) {
str = str + "XYZ";
}
}
Questions:-
Here String str is static, then where this object will be stored in memory?
Since String is immutable, where the object for "XYZ" will be stored?
Where will be final object will be Stored?
And how will garbage collection will be done?
1) Here String str is static, then where this object will be stored in
memory?
Those literals will be stored in the String pool memory, no matter if the variable is declared as static or not.
More info here: Where does Java's String constant pool live, the heap or the stack?
2) Since String is immutable, where the object for "XYZ" will be stored?
Similar to the first answer: a literal will be stored in the pool memory.
Immutability just allows the concept of shared pool memory.
3) Where will be final object will be Stored?
According to the Java specification, concatenation of literals will end up to a literal too (since known at compilation time), stored in the pool memory.
Excerpt:
"This is a " + // actually a string-valued constant expression,
"two-line string" // formed from two string literals
4) And how will garbage collection will be done?
As essence of the pool memory, they won't be garbage collected by default.
Indeed, if garbage collected immediately, the "shared" concept of the pool would fail.
Here String str is static, then where this object will be stored in
memory?
String str is not an object, it's a reference to an object. "ABC", "XYZ" & "ABCXYZ" are three distinct String objects. Thus, str points to a string. You can change what it points to, but not that which it points at.
Since String is immutable, where the object for "XYZ" will be stored?
As explained in above & also by Mik378, "XYZ" is just a String object which gets saved in the String pool memory and the reference to this memory is returned when "XYZ" is declared or assigned to any other object.
Where will be final object will be Stored?
The final object, "ABCXYZ" will also get saved to the pool memory and the reference will be returned to the object when the operation is assigned to any variable.
And how will garbage collection will be done?
String literals are interned. As of Java 7, the HotSpot JVM puts interned Strings in the heap, not permgen. In earlier versions of Java, JVM placed interned Strings in permgen. However, 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.
Shishir

SoftReference<String> not garbage collected when out of memory

I am testing SoftReference for a cache implementation and I found a strange behaviour :
I have a setName(String name) method which sets the name of a Graph object through a SoftReference :
public void setName(String newName) {
getData().name = new SoftReference<String>(newName,garbagedData);
}
(garbagedData is a ReferenceQueue and doesn't seem important in this particular problem).
When I call graph.setName("name"); from main thread, and when à force a OutOfMemory error, the value pointed by the reference is not garbaged but if I call graph.setName(new String("name")) then it is.
I look the heap contents with Eclipse Memory Analyzer and in both case there is no other reference chain than the Soft one.
If anyone has an explanation for this strange behavior I am interested.
That's pretty simple. The string appearing in the source code is interned, i.e., kept in a special pool, and there's no chance to collect it as it's referenced by the code of your method. It's needed when setName gets called again, so it's obviously no garbage.
The situation with new String("name") is very different as this creates a copy of the original String. Actually, there's no need to use this constructor since this change to String.substring.
I guess the Eclipse Memory Analyzer doesn't show references contained in the bytecode (as nobody really needs it).
You are holding a SoftReference to String object. For a String object JVM manages String literals differently from String objects.
String a = new String("test");
String b = new String("test");
In this example instances a and b are references to different objects.
String a = "test";
String b = "test";
Here both a and b are references to same String literal. When you call graph.setName("name"), it is creating a reference to string literal. String objects that refer to String literals generally are not considered for garbage collection. This prevents the String object from getting garbage collected.
When you call graph.setName(new String("name")), it is creating a SoftReference to new String object. Since the reference is to newly created object and not a string literal, it can be garbage collected.

Reclaim first reference of Immutable String

I see many Q&A about Immutable String saying that JVM actually create a new reference when we do the following:
String text = "apple";
text = "orange"; // a new reference is created
My question is, what happen to the previous reference "apple"? Since Java Garbage Collection is automatic, does it means that there is no intentional way to re-claim the memory?
EDIT:
The reason I am asking this question is that I would like to know how should I handle String variables in future.
Does String Literals get cleared by GC? If not, wouldn't the pool going to get so huge until a point where it goes out of memory? Considering if the program receives different string values from a textbox on the UI, each different values that the user enters are going to add on to the pool.
There is no way to intentionally reclaim the memory even with System.gc() (which is just a suggestion to the JVM).
Even when garbage collection runs, "apple" won't necessarily be reclaimed.
According JLS 3.10.5, string literals are interned in a string pool and thus never garbage collected.
Quoting:
A string literal is a reference to an instance of class String (§4.3.1, §4.3.3).
Moreover, a string literal always refers to the same instance of class
String.
This is because string literals - or, more generally, strings
that are the values of constant expressions (§15.28) - are "interned"
so as to share unique instances, using the method String.intern.
EDIT
According to this answer, even interned Strings can be garbage collected.
No, you you can't force the GC to run. One thing it is important to realize is the "apple" String won't be destroyed. It was declared as a literal String, so it will go the String pool.
There is no way to explicitly reclaim a completely dereferenced object. You can call System.gc();, but that's merely a suggestion to perform a gc and not a guarantee that a gc will be performed

Garbage collection of String literals

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.

Categories