1

I am studding and preparing for OCP 1Z0-815 and I read from this excellent preparing book:

Deshmukh, Hanumant. OCP Oracle Certified Professional Java SE 11 Programmer I Exam Fundamentals 1Z0-815: Study guide for passing the OCP Java 11 Developer Certification Part 1 Exam 1Z0-815 (p. 99). Enthuware. Edição do Kindle.

String str = "hello";
for( int i = 0; i < 5; i + +) {
    str = str + i;
} 

The above creates one String object containing "hello" at the beginning and then two more in each iteration of the loop - a String containing the int value of i and the concatenated String. Thus, overall, the above code creates 1 + 2* 5 = 11 Strings. However, if you are asked how many String will be eligible to be garbage collected, the answer is not that easy. The Java Language Specification mentions in Section 15.8.1 that the non-string operand of the + operator is converted to a String at runtime but it does not clearly tell whether this String goes to the String pool (in which case it will not be garbage collected) or not.

Let me show you another piece of code:

String s = "hello";
int k = 100;
s = s + " 123" + k;

In this case, JLS section 15.8.1 clearly says that a compiler may avoid creating multiple strings altogether by making use of a StringBuilder. Thus, it is not possible to tell how many Strings will be created and how many will be eligible to be garbage collected...

The statement above "...The Java Language Specification mentions in Section 15.8.1 that the non-string operand of the + operator is converted to a String at runtime but it does not clearly tell whether this String goes to the String pool..." drove me to search around but I didn't manage to find an explanation: as far as I don't see "new" I understand that indeed it goes to String pool and so it is not an object. Consequentlly it is not elegiable for garbage collection at all. Am I saying something wrong?

In other words, as far as understand, every loop will result in a constant string in String Pool in Heap (Java 11 in mind instead of Java 7). hello0, hello1, hello2 and so on and there will not be any candidate for Garbage Collection at all. I understand that Garbage Colletion "clean" objects created by new operator and doesn't act on String Pool.

Based on conclusion paragraph, "... section 15.8.1 clearly says that a compiler may avoid creating multiple strings altogether by making use of a StringBuilder. Thus, it is not possible to tell how many Strings will be created and how many will be eligible to be garbage collected..." I assume it is saying that I can't discover how many Strings are created in String Pool in second code example (wihtout loop) because StringBuilder is used behind the scene and we know that StringBuilder manipulate concatenation in memory avoiding creating many String literals. Well, if that is the case, I still can assume in first code thatt fofr each loop will result in a Literal String (hello0, hello1...) that goes to String Pool and will not be eligible for Garbage Collection in pratical terms. Am I wrong?

PS.: You may comment that Garbage Collection acts on String Pool but I understand that in pratical terms, literal string in String Pool resides for a so long time that we can consider it is never eligible for Garbage Collection before program ends (" there is an implicit reference to the String object in the code of every method that uses the literal." and " all string literals in the string pool are reachable until the program is terminated and thus not eligible for garbage collection"

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Jim C
  • 3,957
  • 25
  • 85
  • 162
  • 2
    I really wish they would stop putting these "how many objects are created / eligible for garbage collection" into the OCP and study material. They are often asked in an ambiguous way and they usually don't have a single correct answer that applies to all Java implementations. – Stephen C Oct 09 '19 at 13:33
  • Stephen, according to book Author, "Don't worry, you will not get questions in the exam about garbage collection of Strings. I have talked about it here only to make you aware of the issue. Strings muddle the topic of garbage collection so much so that it is a bad idea to use them while explaining garbage collection. You need not spend anymore time on this topic". By the way, I am trying to understand the point mentioned in my question. As mentioned in same book, "...Java 7 onwards, strings in the string pool can also be garbage collected" but I am a bit confused specially when "+" is involved – Jim C Oct 09 '19 at 14:00

1 Answers1

4

as far as I don't see new I understand that indeed it goes to String pool and so it is not an object.

First of all, the Java Language Specification doesn't mention the string pool specifically. What it actually says is that if two string-valued constant expressions are equal, then they will be the same object. (This covers string literals, but also covers cases like String s = "a" + "b";)

The string pool is >>a<< mechanism for doing that, but the JLS doesn't mandate a specific mechanism.


What about new?

The JLS also says that the new operator always produces a brand new object:

"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." (JLS 15.9.4)

The consequence of this is:

String a1 = new String("a");
System.out.println("a" == a1);   // prints "false"

This must be do, because the new String is not a fresh one. Since the string pool is a de-duping mechanism, we can conclude that new String("a") is NOT putting the new String object into the string pool.


Likewise, the + operator creates a new String:

"The result of string concatenation is a reference to a String object that is the concatenation of the two operand strings. The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string." (JLS 15.18.1)

The JLS also says that the compiler can optimize expressions involving +:

"An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.

For primitive types, an implementation may also optimize away the creation of a wrapper object by converting directly from a primitive type to a string." (JLS 15.18.1)

But note that this optimization is only permitted within an expression, not across multiple statements.


The JLS says nothing about other String operations. For their specification we need to refer to the javadocs. In current versions, the only String methods that state that a new string is always created are the two join methods.

But likewise, the only String method that specifically mentions the string pool is the intern method.


That is what the specifications say. What do String implementations actually do?

Well if you examine the standard source code for Java SE implementations going back to Java 1.1, you will find that apart from intern, no String methods put objects into the string pool. None.


You also said this:

I understand that in practical terms, literal string in String Pool resides for a so long time that we can consider it is never eligible for Garbage Collection before program ends.

That is true is most cases. The exception is code that is you can create a classloader and use that to load classes dynamically. If that classloader becomes unreachable, and there are no other references to the classes it loaded, then its string literals may be unreachable ... before the program ends.

This is liable to happen if you use a product (e.g. a web container) where new versions of classes can be hot-loaded.


Finally if we look at the example:

   String str = "hello";
   for (int i = 0; i < 5; i++) {
       str = str + i;
   } 

In practice:

  1. The first time we run this, a new String object will (probably) be created for the "hello" literal.

  2. On each loop iteration, at least one new String will be created. It is possible that an intermediate String will be created to represent the string value of i, but the compiler is permitted to optimize that away.

  3. None of the intermediate String objects will be interned / added to the string pool.

  4. All but the "hello" literal and the final value will be unreachable.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Excellent explanation. But, maybe because I am not that level of expertise, I still don't see answer to my main question. I totally understand that no intermediate String will go to String pool. And the result ones? Will it go to String Pool (I am talking about hello0, hello1,... hello4)? I guess yes unless you mean hello0...4 are intermediate String. It is clear to me that they will be keeped in Spring Pool after the loop finishes (well if it is worth may be other question since very probably not be used again but they will indeed be in String Pool, right?). – Jim C Oct 09 '19 at 15:23
  • Not directly related to my question, but I believe it is worth to mention that surprised me a lot: the Java Language Specification doesn't mention the string pool specifically. Well, since String Pool is not a third implementation (for instance, something implemented by Spring team) and a very native topic to Java (it was moved to Heap in Java 7 to deal with common and well-known issues) that even the releases touch on it I am wondering why it is not part of JAVA SE. Maybe I understood wrongly your comment – Jim C Oct 09 '19 at 15:29
  • 1
    The direct answer to your direct question is No. Because the JLS requires that `+` creates a new string (always). If it put the result into the string pool then it wouldn't always be a new string. The only thing that will put a string into the string pool is an explicit call to `intern`. – Stephen C Oct 09 '19 at 23:24
  • 1
    The string pool is not an separate implementation of strings. In fact in Java 8 and later it is just a (private) de-duping data structure that holds references to ordinary strings. – Stephen C Oct 09 '19 at 23:29
  • Honestly, I don't understand what you really mean by "...it is just a (private) de-duping data structure that holds references to ordinary strings...". I will study later the term "de-duping data structure". I will avoid extend this term here since it is not straigh to my question and probably unnecessary for my certification goal – Jim C Oct 10 '19 at 16:09
  • Thanks a lot, I consider "The direct answer to your direct question is No" as final answer to my question and " Because the JLS requires that + creates a new string (always)" the reason. Regard your statement "The only thing that will put a string into the string pool is an explicit call to intern" I believe you are talking only about hello0, hello1... Certainly we agree that the line "String str = "hello";" will result in a static value "hello" in String Pool unless there is already "hello" in String Pool. – Jim C Oct 10 '19 at 16:14