Win a copy of The Java Performance Companion this week in the Performance forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Immutability behavior of a String object

 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,

I am reading HeadFirst Java and there's one section about String immutability that I'm a little bit confused.

There's one example:


The book says that it's creating ten String objects ("0", "01", "012", "0123", through "0123456789").
In the end s referring to "0123456789"
It says that whenever I make a new String, JVM will put it in String pool.

Ok, this makes sense so far.

But then it says that the garbage collector doesn't go to the String pool. This is where I'm confused.

#1.)
I thought what should happen is more something like this:
1. Create String "0".
2. Create new String "01", "0" no longer referenced by anybody, so it's candidate for garbage collector.
3. And so on.

#2.)
And if what it says is true (garbage collector doesn't go to the String pool), then who clean up all those Strings("0", "01", "012", "0123", through "0123456789").
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24211
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Susan Smith:

It says that whenever I make a new String, JVM will put it in String pool.



No, it doesn't actually say that. It says that String literals like "0" will be held in the String pool; the Strings you're creating in the loop will not be.


#1.)
I thought what should happen is more something like this:
1. Create String "0".
2. Create new String "01", "0" no longer referenced by anybody, so it's candidate for garbage collector.
3. And so on.


That's true for every time around the loop except the very first time; the "0", being a literal, is in the String pool, so it's not collected. All the other ones are.
 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ernest, thank you for your reply.

1.)
I think it really does saying that on page 589.
Whenever you make a new String, the JVM puts it into a special part of memory called the 'String Pool'


2.)
That's true for every time around the loop except the very first time; the "0", being a literal, is in the String pool, so it's not collected. All the other ones are.

So even though "0" is no longer referenced by anybody, it will be still around in the memory?
I'm still confused about this. Could you please give me some more explanation?

Thanks again.
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[EFH]: No, it doesn't actually say that.

It certainly shouldn't say that, but it's possible that it does say it anyway. I recall seeing something similar in the SCJP book by the same authors. Perhaps they mis-stated it the same way in both books. I don't have either book available to check at the moment.

[Susan]: But then it says that the garbage collector doesn't go to the String pool.

That's also not true. Though it is true that strings in the pool are stored in a special area, known as the permanent generation, where garbage collection occurs infrequently - because most of the object there are expected to be around for the life of the JVM, probably. But it is possible for strings in the string pool to be garbage collected, in certain cases. If you're using different classloaders, for example, then when a class is unloaded, String literals from that class become eligible for GC. Or if you simply intern() a lot of Strings, without saving any other references to them - those are also eligible for GC.
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[Susan]: So even though "0" is no longer referenced by anybody, it will be still around in the memory?

"0" is still referenced by the class definition itself. If anyone calls that method again (or constructor or whatever that code is in) then "0" needs to be available as a constant. It will only go away if the entire class becomes unloaded (as can happen in an application server).
 
Alan Moore
Ranch Hand
Posts: 262
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It really does say that (it's on page 661 of the second edition), but it's wrong. Only String literals like "0" and compile-time constants (i.e., static final String variables) are automatically cached in the String Pool. The strings that are created in the for loop in that example will be eligible for gc as soon as all the references to them go out of scope.
 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For the String literal, How about if I have something like these in the code?

String literal as argument/ parameter
1.)
2.) |

Those above will be considered String literal?

Or is it only for something like this



-----------------
You also mentioned:
and compile-time constants (i.e., static final String variables)


How about String literal for data member?
Example:
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24211
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A String literal is any sequence of characters surrounded by double quotes that appears in Java code, no matter where. Every one of your examples includes a String literal. That String is always stored in the String pool, as long as your class is loaded into the JVM.
 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I found this excellent article: http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html
 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think this is very interesting.

It means that it is also the same case with some of the debugging code that I have in some of my programs: or some log4j

I also have a console based program that uses a lot of Pattern objects. If I want garbage collector to collect it, then instead of doing this:

I should do this:
 
Campbell Ritchie
Sheriff
Pie
Posts: 49451
64
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Writing new String("lalala") won't encourage garbage collection; the "lalala" literal remains regardless.

I think you are best to forget about garbage collection, and leave the JVM to do it. It is happiest when left to work its own way, and keeping a String or two in memory won't do any harm.
In fact there is a slight performance overhead from creating a new String and garbage collection later which you can avoid by using a String literal straight.

A lot of people think there is no point in writing new String("lalala") ever (well, hardly ever); you just write "lalala".
[ August 01, 2008: Message edited by: Campbell Ritchie ]
 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This leads me to a question:

Is there any tool I can use to investigate what's actually inside the heap and /or stack?
I want to improve the performance of my console-based program and I'm thinking if I can know what's inside the heap and/ or stack, I can get more clear picture of what's going on underneath.
 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I've tried using JConsole but it doesn't tell me what's inside the heap and/ or stack.
It only tells me the memory usage.
 
Carey Evans
Ranch Hand
Posts: 225
Debian Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Try VisualVM from the very latest Sun JDK 6.
 
Susan Smith
Ranch Hand
Posts: 224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
(1.) Thank you. I will try VisualVM.

(2.)
Is doing String manipulation best done using StringBuffer than String?
Will it save memory?
For example, I have a lot of replaceAll statement like this below in my code:
 
Bill Shirley
Ranch Hand
Posts: 457
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Use a StringBuilder if execution time is important.

sb.append("foo")
or
s = s + "foo"

still create the string literal "foo"

(I would define a string literal simply as "any string the COMPILER sees". It's the part of the in-memory code image, so cannot be "collected".)
 
Alan Moore
Ranch Hand
Posts: 262
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Susan Smith:
(2.)
Is doing String manipulation best done using StringBuffer than String?
Will it save memory?
For example, I have a lot of replaceAll statement like this below in my code:

If you're doing several related replacements, you should definitely try do them all in one pass instead of calling replaceAll() several times. The Matcher class contains lower-level methods you can use to accomplish that. For example, if you wanted to replace all of the strings "eastbound", "westbound", "northbound" and "southbound" with their abbreviations, you could do this: (Note that I only used StringBuffer because that's what the methods expect; ordinarily I would use a StringBuilder.)

For a simpler and more flexible way to do this kind of thing, you can use Elliott Hughes' Rewriter. It's essentially a pre-packaged version of what I just wrote.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic