2

I understand how String pool and intern() method works in java. Here is a brief introduction.

String.intern() in Java 6

In those good old days all interned strings were stored in the PermGen – the fixed size part of heap mainly used for storing loaded classes and string pool. Besides explicitly interned strings, PermGen string pool also contained all literal strings earlier used in your program (the important word here is used – if a class or method was never loaded/called, any constants defined in it will not be loaded).

The biggest issue with such string pool in Java 6 was its location – the PermGen. PermGen has a fixed size and can not be expanded at runtime. You can set it using -XX:MaxPermSize=96m option. As far as I know, the default PermGen size varies between 32M and 96M depending on the platform. You can increase its size, but its size will still be fixed. Such limitation required very careful usage of String.intern – you’d better not intern any uncontrolled user input using this method. That’s why string pooling at times of Java 6 was mostly implemented in the manually managed maps.

String.intern() in Java 7

Oracle engineers made an extremely important change to the string pooling logic in Java 7 – the string pool was relocated to the heap. It means that you are no longer limited by a separate fixed size memory area. All strings are now located in the heap, as most of other ordinary objects, which allows you to manage only the heap size while tuning your application. Technically, this alone could be a sufficient reason to reconsider using String.intern() in your Java 7 programs. But there are other reasons.

Source

OK up to this point I am comfortable with how Strings are stored in memory until I came across this tool Java Visualizer. I wrote up following simple Java class to visualize how memory is allocated in a program.

public class A {

   String iWillAlwaysBeOnHeap="I am on heap...!!!";


   class Dummy{

      private int dummyNumber;

      Dummy(int dummyNumber)
      {
         this.dummyNumber=dummyNumber;
      }
   }

   public static void main(String[] args) {
      A a=new A();
      a.lonelyMethod();
   }


   public void lonelyMethod()
   {
      String lostString="dangling";

      String test=new String("dangling");

      test.intern();

      String duplicateLiteral="dangling"; 

      Dummy dummy=new Dummy(4);
   }


}

And I got the following results:

Visualizer Output

As you can see String literals and objects with the same values are repeated and stored on stack and heap space does not come into the picture for method local Strings. I was confused at first but then I searched and found out about escape analysis which is done by JDK 7 automatically. But in my code I have created a String object which should be stored on heap but it is on stack as you can see in visualizer output but my Dummy class object is stored on heap. I could not really grasp this behavior. How are method local strings treated differently than other objects and instance level Strings?

Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
Dangling Piyush
  • 3,658
  • 8
  • 37
  • 52
  • 1
    _"in my code I have created a String object that is stored on stack"_ -- No you didn't. To repeat the docs that you yourself cite: _"All strings are now located in the heap"_. (That's in Java 7; in earlier versions, strings might be in the heap or in PermGen, but never on the stack.) – Ted Hopp Aug 08 '14 at 17:30
  • @TedHopp Ok I correct myself "I have created a String Object which should be stored on heap but It is on stack as you can see in visualizer output" sorry for my bad english..edited the same.. – Dangling Piyush Aug 08 '14 at 17:34
  • You need to do `test = test.intern();` to remeber the reference to the interned version. – eckes Aug 10 '14 at 01:18
  • They way objects are stored by the Java Runtime is not linked to the semantics of String#intern and references. For example VMs can do escape analysis and don't put locally allocated/used temprary objects in the heap at all. For a Java programmer this magical optimizations are transaprent in most cases (and optimizing based on a wrong undersatanding often inhibits things like that). – eckes Aug 10 '14 at 01:20
  • The Visualizer is nice, but it does not represent reality (neither the logical model nor the physical) correctly. It does not treat strings as objects and it does not know about string pool. – eckes Aug 10 '14 at 02:06

1 Answers1

1

I think you are misinterpreting the visualizer output. What's on the stack are three references to string objects, corresponding to the three local variables in lonelyMethod. It seems that "for your convenience", Java Visualizer displays the string representation of the referenced object, but that's not what's actually on the stack. The objects that are referenced all look identical, but two of them reference the interned string "dangling" and the third (actually the second, corresponding to variable test) references a separate String object on the heap.

I suppose Java Visualizer could have displayed the identity hash code for each object reference on the stack, but that would (usually) be less useful. Perhaps there's a setting in the visualizer to enable such behavior. It would help clarify what's going on.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • What about http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html ? Escape analysis ? Is it not happening for my code? – Dangling Piyush Aug 08 '14 at 18:11
  • @DanglingPiyush - Escape analysis is specific to the HotSpot Java compiler. The Java Visualizer tool doesn't use that compiler; as far as I can tell, it has its own internal compiler (which probably does absolutely no optimizations). – Ted Hopp Aug 08 '14 at 19:24