javacaps mock exam 1, #12: From the following code how many objects are eligible for garbage collection? String string1 = "Test"; String string2 = "Today"; string1 = null; string1 = string2; A) 1 B) 2 C) 3 D) 0 ANSWER: A ------ Shouldn't it be D, since creating strings without using null creates them on the heap, not the stack. Hence, they are ineligible for garbage collection. Thank you for any replies.
Rodge Thomas
Ranch Hand
Joined: Jul 25, 2002
Posts: 38
posted
0
So sorry. I meant to type: "without using new", not "without using null"
Anthony Villanueva
Ranch Hand
Joined: Mar 22, 2002
Posts: 1055
posted
0
Hi Rodge, the pencil and paper icon allows you to edit your posts. Anyway, Java objects are never placed on the stack.
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
I thought string literals lived in the string pool and are therefore never garbage-collected.
Ron Newman - SCJP 1.2 (100%, 7 August 2002)
Barkat Mardhani
Ranch Hand
Joined: Aug 05, 2002
Posts: 787
posted
0
The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class.
Above is a quote from String Class description. So the code in your question is actually creating new objects of String class and hence candidate for garbage collection... Hope this helps... Thanks Barkat
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
Yes, string literals are String objects, but that doesn't mean they are garbage-collected. [ August 15, 2002: Message edited by: Ron Newman ]
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
From the Java Language Spec: 3.10.5 String Literals ... Each string literal is a reference (�4.3) to an instance (�4.3.1, �12.5) of class String (�4.3.3). String objects have a constant value. 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 says to me that the interned strings live forever -- they are not GC'd. [ August 15, 2002: Message edited by: Ron Newman ]
Barkat Mardhani
Ranch Hand
Joined: Aug 05, 2002
Posts: 787
posted
0
Hi Ron: Try following program:
You will see that free memory is periodically restored. That infers that gc has run and released some memory. Also more detailed quote from String Class Description:
The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class. Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. For example:
This clear indicates that objects created with: String str = "abc"; are same as created by String str = new String("abc"); Therefore, I believe that objects in original question are also garbage collectables... Hope this makes it clear.. Thanks Barkat [ August 15, 2002: Message edited by: Barkat Mardhani ]
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
Your program creates a bunch of Strings and StringBuffers every time you call that println() statement. That's what is being garbage-collected, not copies of "abc".
Barkat Mardhani
Ranch Hand
Joined: Aug 05, 2002
Posts: 787
posted
0
Hi Ron: You made a good point. But if copies of "abc" are being piled up, then free memory should have a net negative trend which I did not observe. Run following code:
Also, there is no way of knowing for sure that gc is cleaning up just the strings created by println or that plus copies of "abc". Also, creator of question (in Rodge Thomson's initial note) is assuming that these are garbage collectable objects. Also as per String Class description (in note above), a assertion is being made that two statements have same effect; meaning both of them will create same object, hence they should be treated in same manner by gc. Has anyone else any more evidence to prove it one way or other... Thanks Barkat [ August 15, 2002: Message edited by: Barkat Mardhani ]
Valentin Crettaz
Gold Digger
Sheriff
Joined: Aug 26, 2001
Posts: 7610
posted
0
Just to clear things up (in case they weren't clear before :roll: ): String literals, that is, strings having a constant value AT COMPILE_TIME are automatically interned (intern() is automatically invoked on them) and are not garbage-collectible until the JVM exits. For instance, the following strings are not garbage-collectible String literals: String s1 = "some_literal"; String s2 = "" + SOME_PRIMITIVE_CONSTANT; String s3 = s1 + s2; (See JLS 3.10.5 String Literals for more examples) Even though we use the concatenation operator, all of the above Strings are true String literals, because the compiler has all the necessary information to construct them at compile-time. Side note: I would like to add that there is a bug in the API documentation for class StringBuffer where it is stated that:
String buffers are used by the compiler to implement the binary string concatenation operator +. For example, the code: String x = "a" + 4 + "c" is compiled to the equivalent of: String x = new StringBuffer().append("a").append(4).append("c").toString() which creates a new string buffer (initially empty), appends the string representation of each operand to the string buffer in turn, and then converts the contents of the string buffer to a string. Overall, this avoids creating many temporary strings.
Unfortunately, the example Sun is taking is very badly chosen since the compiler is able to resolve by itself the literal "a" + 4 + "c" because all elements are constants known at compile-time. If you cut-paste the above code, compile it and decompile it, you'll see that there is not trace whatsoever of StringBuffer within the decompiled byte code. For convenience, I add the decompile code below:
As you can see, the String literal "a4c" has been resolved by the compiler. Now, I have slightly changed the code to
If we compile and decompile it, we get the following:
The result speaks for itself Anyway, I have digressed a little bit, but the bottom line is that String literals are never garbage-collected until the JVM is exiting. A good way to see this, would be to look at the C source file which is natively handling String interning. Those sources are not available from Sun, but they are from Kaffe. This is not required for SCJP but it is a very good exercise for anyone who would like to push the challenge a little bit further. For those who are interested, once you have downloaded the kaffe-1.0.7.tgz file, have a look at the C source file named kaffe-1.0.7\kaffe\kaffevm\string.c . Interesting isn't it?
Hi Valentin, Ron: I have following questions: a. The following statement will create String literal on the heap or stack? String S = "abc"; b. Are following references pointing to same object or two identical but distinct objects: String S1 = "abc"; String S2 = "abc"; c. How many distinct objects will be created by following: for (int i=0 ; i<6 ; i++) String S = "abc"; Thanks for your help to understand this concept clearly. Barkat
Valentin Crettaz
Gold Digger
Sheriff
Joined: Aug 26, 2001
Posts: 7610
posted
0
a. The following statement will create String literal on the heap or stack? String S = "abc"; Objects are always created on the heap. b. Are following references pointing to same object or two identical but distinct objects: String S1 = "abc"; String S2 = "abc"; S1 and S2 are pointing to the same object on the heap. Try S1 == S2 and you will see. c. How many distinct objects will be created by following: for (int i=0 ; i<6 ; i++) String S = "abc"; 1
Barkat Mardhani
Ranch Hand
Joined: Aug 05, 2002
Posts: 787
posted
0
And one more question: d. How many distinct objects are now created: for (int i=0 ; i<6 ; i++) String S = new String("abc"); Thanks, Barkat
Valentin Crettaz
Gold Digger
Sheriff
Joined: Aug 26, 2001
Posts: 7610
posted
0
d. How many distinct objects are now created: for (int i=0 ; i<6 ; i++) String S = new String("abc"); 6 because the new keyword is used. [ August 16, 2002: Message edited by: Valentin Crettaz ]
Barkat Mardhani
Ranch Hand
Joined: Aug 05, 2002
Posts: 787
posted
0
Great, now I am getting the idea. In the final analysis, will you guys agree that: 1. My code above is NOT creating billion plus copies of "abc". It is just creating one object "abc" and pointing to it billion plus times. 2. The object created with : String S = "abc"; is not garbage collectable even after S points to another object. 3. Rodge Thomson's observation (above) is correct that answer to the question should be D not A. Thanks Barkat
Valentin Crettaz
Gold Digger
Sheriff
Joined: Aug 26, 2001
Posts: 7610
posted
0
That's correct
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
That's right. And someone should tell the author of this mock exam question. Where did you find it?
Rodge Thomas
Ranch Hand
Joined: Jul 25, 2002
Posts: 38
posted
0
It is from javacaps.com I emailed them a link to this post.
Jose Botella
Ranch Hand
Joined: Jul 03, 2001
Posts: 2120
posted
0
Fortunately it's nothing to do with the exam but string literals can be g.c.ed donwloading the class that declared them. The string objects resulting from compile constant expressions are referred from the constant pool of the class. The constant pool isn't the string pool, but it acts like the symbol table of others languages. If you download the class these references are also cleaned. The bytecodes ldc #4 and ldc #6, shown above, use these references I'am talking about. I think the bytecode stands for LoaD from the Constant pool. [ August 17, 2002: Message edited by: Jose Botella ]
SCJP2. Please Indent your code using UBB Code
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
string literals can be g.c.ed donwloading the class that declared them.
I don't unerstand this -- why would "downloading" a class (from the Internet?) cause anything to be garbage collected?
Jose Botella
Ranch Hand
Joined: Jul 03, 2001
Posts: 2120
posted
0
Sorry, I didn't mean downloading but unloading. Unloading the class from the VM means that classes can be g.c.ed as well. Here is the post that shows how. Again this is not tested in the exam. JFYI.
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
What does it mean to "unload" a class? What is the purpose of doing so? If I wanted to unload, say, StringBuffer or PrintWriter, how would I do it?
Jose Botella
Ranch Hand
Joined: Jul 03, 2001
Posts: 2120
posted
0
You need to load a class in a class loader of your own. And later, because a class loader holds a reference to all the classes that loads, it's necessary to set the class loader to null as well. There is an example im my previous link. Again, none of this is exam stuff.
Barkat Mardhani
Ranch Hand
Joined: Aug 05, 2002
Posts: 787
posted
0
Hi Hose: If you see my posts (couple of screens above), you will see that by writing and testing a similar (to your) program, I came to conclusion that string literals are g.ced. Thanks Barkat
Jose Botella
Ranch Hand
Joined: Jul 03, 2001
Posts: 2120
posted
0
Barkat, your program doesn't garbage collects string literals because the class that declare them wasn't unloaded. The class still has a reference to the string literals, in its constant pool, when the g.c. runs. I thought you have agreed with Val in your last post.
Patrick Ansari
Greenhorn
Joined: Feb 23, 2002
Posts: 8
posted
0
I'm getting false and not true. Am I missing something here? private void doStuff() { String s1 = "abc"; String s2 = "abc"; System.out.println("s1 == s2 : " + s1==s2); }
Patrick Ansari
Greenhorn
Joined: Feb 23, 2002
Posts: 8
posted
0
ok interesting - so why does my previous post evaluate to false if this: System.out.println(s1==s2); evaluates to true?
Patrick Ansari
Greenhorn
Joined: Feb 23, 2002
Posts: 8
posted
0
System.out.println("s1 == s2 : " + (s1==s2)); something to do with order precedence? becuase this here works just fine with the parenthesis. output: s1 == s2 : true
Barkat Mardhani
Ranch Hand
Joined: Aug 05, 2002
Posts: 787
posted
0
Hi Hose: I agreed with Val because I am not that experienced and I did not have any way of knowing which "object" are actually being cleaned up by GC. Also Val maintained that my program was not creating billion plus String literal objects "abc". It was actually creating one and keep on pointing to it again and again. And Val said that that single string literal "abc" is never GCed. I believe what you are saying is that if you unload the class that created this particular string literal then it is candidate for garbage collection. In posts above, by Patrick, it is evident that s1 and s2 are point to same object therefore s1==s2 evaluates to true. But Hose how are you certain that after unloading corresponding class the string literal "abc" is actual being GCed. In other words, is there any way of finding out which obects are actually GCed? Thanks Barkat
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
Addition has higher precedence than equality, so this parses as
Barkat, with java.lang.ref.WeakReference.get() is possible to know when an object is ready/about to be g.c.ed When the g.c. encounters an object that is referred only by weak references(1) it clears these references. The get method returns now null. ___________ (1) weak or phantom references I think
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
If someone could explain the difference between Weak and Soft references, I'd greatly appreciate it. I actually asked such a question over in Intermediate but nobody has answered it.
Jose Botella
Ranch Hand
Joined: Jul 03, 2001
Posts: 2120
posted
0
I was going to write something. But API explains it better than me. What a relief! [ August 19, 2002: Message edited by: Jose Botella ]
Ron Newman
Ranch Hand
Joined: Jun 06, 2002
Posts: 1056
posted
0
I've read both the SoftReference and WeakReference API documents and still don't understand the difference between the two.
Jose Botella
Ranch Hand
Joined: Jul 03, 2001
Posts: 2120
posted
0
Let me copy because I am a lazy man.
* An object is strongly reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strongly reachable by the thread that created it. * An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference. * An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization. * An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it. * Finally, an object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways.
Let's suppose an object is pointed by a strong reference and by a weak one. Calling get() on the weakReference will return an strong reference to it. Imagine the object looses its strong reference. You can still access to it through the get method. Nothing happens untill the g.c. runs because of scarcety of memory. When the g.c. encounters an object that isn't reachable via strong references but it is via weak ones, it clears all weak references pointing to it. Also it make the object finalizable. Now the get method will return null. The object isn't pointed by any weak or strong reference and can be finalized and later g.c.ed So what? are you asking yourself. Thanks for your patience so far. Note that the object has gone from an state in which it was strongly (normally) reachable, to an state in which it can be g.c.ed -if the g.c. runs due to memory neeeds, though alternatively it can be used again via the get method -if the g.c. haven't run. If using strong references, instead of weak, the g.c. could end up in a OutOfMemoryError more easily. With weak references it is allowed to collect more objects, the pointed by weak references. However WeakRefernces are used for canonicalizing maps as the API for WeakHashMap explains. The difference with SoftReferences is that the g.c. won't clear the reference to the object and it wont' make finalizable the object as soon as it determines it is softly reachable. The g.c. will only proceed to do that if the there is necessity for more memory than available. SoftReferences are used to construct caches sensible to (the lack of) memory. You can read much more on the online chapters of Inside the Java 2 Virtual Machine by Bill Venners here It follows a little program: