• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Rob Spoor
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Henry Wong
  • Liutauras Vilda
  • Jeanne Boyarsky
Saloon Keepers:
  • Jesse Silverman
  • Tim Holloway
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Mikalai Zaikin
  • Piet Souris

String pool question

 
Ranch Hand
Posts: 401
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi.
Is the pool of literal Strings created on the heap?
 
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, it is never physically created.
The "String literal pool" is merely a conceptualization technique, though one might argue that "the pool" exists in the bytecode.

String literals have an object (on the heap of course) created as they are used. Even the same String literal may not use the same String instance (contrary to JLS 3.10.5).
 
Leandro Melo
Ranch Hand
Posts: 401
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Tony Morris:
Even the same String literal may not use the same String instance (contrary to JLS 3.10.5).



I thought there was no repeated String literals in memory...?
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, so do a lot of people (in line with the JLS).
This is not the case however in the Sun implementation.
When the specification and the reference implementation contradict, go with the reference implementation.
 
Ranch Hand
Posts: 1272
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So why does this work?:
String a = "abc";
String b = "abc";
if ( a == b ) System.out.println( "It works!" );
 
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I quote the Java Language Specification:


20.12.47 public String intern()
A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals method (�20.12.9), then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.

All literal strings and string-valued constant expressions are interned (�3.10.5).



This text is also present in API documentation for String under the intern method.
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As Strings literals are mantained in string pool of the String class, string objects won't be elegible for garbage collection until String class is unloaded.

Strangely the intern method of the class String is declared native and we cannot see the implemention of the method in the API. For some reason the API does not says the method is native. I have not found much information regarding what exactly is the string pool besides this. I gues the jvm handles this string references in some sort of structure bound to the class String. But of course, I have not based this information in any trustable source.
 
Ranch Hand
Posts: 243
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Perhaps this would add something more...
https://coderanch.com/t/375744/java/java/better-way-representing-empty-string
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


As Strings literals are mantained in string pool of the String class, string objects won't be elegible for garbage collection until String class is unloaded.



This is false.
 
Mike Gershman
Ranch Hand
Posts: 1272
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Tony, you have made several statements about string pools that don't match my understanding, but I'm always looking to learn more. Can you post a reference we can look at.
 
Ranch Hand
Posts: 1071
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have heard Tony's claim before and have, as of yet, seen nothing to make me think it is correct.
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
bleh, I proved it on another thread.
The code is there somewhere.
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To be honest, I'm really over it, but people continue to be misled and that's their business.

In any case, try this.
Hopefully you can draw some reasonable conclusions from the observed results.

 
Steven Bell
Ranch Hand
Posts: 1071
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I really don't see how that proves anything. As mentioned before the 'String pool' is held in the String class, so wouldn't it be reasonable for different ClassLoaders to possibly end up with different String classes?

And if there is no pool wouldn't all String literals end up being references to different objects? After all if there is no pool there would be no reference left to a String once that String had gone out of scope. That String would be elegible for gc and you would not be able to get a reference to that String back.
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Tony, if you've got any examples or references demonstrating that String literals can be garbage collected without the class itself being unloaded, I'd certainly be interested in seeing them.

[Update: this was based on my misreading of Edwin's post above. It's retracted now. - Jim]
[ March 21, 2005: Message edited by: Jim Yingst ]
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Steven]: As mentioned before the 'String pool' is held in the String class, so wouldn't it be reasonable for different ClassLoaders to possibly end up with different String classes?

Mmmm, I don't think so. I believe you'd have a vary hard time getting two different versions of the String class in the same JVM at the same time. The problem is that any classloader you create will have a parent classloader. If you don't specify a parent, you get the system clasloader (which is ultimately the ancestor of all classloaders you will ever get). The parent gets first crack at loading any class you request - and the system classloader will definitly be able to provide java.lang.String. Sun set things up this way specifically to prevent people from redefining standard libraries. (Of course you could always replace rt.jar on your system, but I would submit that would mean we're no longer discussing the reference implementation.) So, there should only be one String class loaded on any given JVM. As far as I know, anyway.

It looks like in Sun's implementation, String pools exist on a per-ClassLoader basis. There's only one String class, but there can be more than one pool.
 
Steven Bell
Ranch Hand
Posts: 1071
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jim Yingst:

It looks like in Sun's implementation, String pools exist on a per-ClassLoader basis. There's only one String class, but there can be more than one pool.



That sounds reasonable and would seem to account for the observed behavior.
 
Ranch Hand
Posts: 5093
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Different classloaders should yield distinct instances of the Class object related to a class even for the standard API.
Given the assumption that the String pool for any given instance of the String Class is controlled by that Class object (not unreasonable) you should get more than one pool if creating several String literals controlled by several classloaders.
Maybe using 2 default classloaders the compiler will optimise the classloaders away but Tony uses URLClassLoaders in which case this isn't possible as the classes may be loaded from remote sources.
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Jeroen]: Different classloaders should yield distinct instances of
the Class object related to a class even for the standard API.


Not according to the API as far as I can see - it explicitly describes how parent classloaders must be consulted. If the parent loader can supply a class, that's the class that's used, and the child loader is not consulted further. So it the system class loader has a class defined, that's it - you can't redefine it. As far as I can tell anyway. tt's easy to test this, based off Tony's code. Just insert this code somewhere after each ClassLoader was created:

I get the same hash code twice - indicating it's extremely likely these
are in fact the same object.

Experimenting further with Tony's code, it's interesting to note that if we comment out the explicit call to System.gc(), it looks like only one String instance is created for the two literals. (As originally expected.) This would seem to indicate that, contrary to my last post, there is not a separate string pool for each class loader. There's one pool, but if a class is unloaded, then associated string pool instances are subject to garbage collection. We can verify that class X is unloaded in Tony's code, before Y is loaded. Just run with java -verbose:gc and examine the output. X is unloaded, java.lang.String is not. So now, to revisit a previous comment:

[Edwin]: As Strings literals are mantained in string pool of the String class, string objects won't be elegible for garbage collection until String class is unloaded.

[Tony]: false


The main problem with Edwin's post seems to be "until String class is unloaded". Pooled strings appear to be eligible for unloading when the class that declares them is unloaded. Which is what I originally thought that Edwin had said; hence my subsequent question to Tony about this. Withdrawn.
 
Steven Bell
Ranch Hand
Posts: 1071
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Something I find to be interesting. Whenever I run Tony's code from the command line I get the exact same numbers he has posted, every time. When I run it from eclipse I get different numbers, but they are also very repeatable, I have yet to see them vary.

Anybody want to take a shot at explaining that? Anybody else get the same results?
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, the results are probably determined by what JVM addresses are used to store the objects. (That's not guaranteed, but it's a reasonable supposition.) This is determined by several things: how does the JVM allocate addresses, including what command-line options have been invoked, and what memory has already been used in the JVM. I assume we're using the same JVM version, or close enough that it doesn't matter. But when you run from eclipse (or IntelliJ or whatever) the IDE may have caused other classes to be loaded prior to running your main() method. Or it may have used the -Xms option to start with a different amount of heap memory. Either way, the layout of the heap is different, and the addresses that it uses to store new objects may be different.
[ March 21, 2005: Message edited by: Jim Yingst ]
 
Steven Bell
Ranch Hand
Posts: 1071
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hmm, playing around a bit more. I added some String literals at the top level, didn't seem to change anything. Made some method calls on them, no change. But when I created an Object and called a method on it I got different numbers (I'm guessing I had to call the method so that the Object didn't get optimized away, but that's only a guess).

I'm guessing Tony is using 1.5 (based on the generics and varargs). I'm running 1.4.2_03 (had to change the code a bit for it to run). I'm a little interested in what is going on here, but probabaly not interested enough to look up the source for the Object hashCode method, it being native.

Also I didn't recompile from the command line, the class file was always compiled from eclipse.
reply
    Bookmark Topic Watch Topic
  • New Topic