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 poolnew 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?
CodePudding user response:
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.
CodePudding user response:
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 methodString.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 methodString.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.