The Evolution of the Java Memory Architecture
Let's take a trip through through time to see how Java's memory architecture has grown from generation to generation, from pre-Java 7 to Java 8.
Join the DZone community and get the full member experience.Join For Free
Note: Before we get started, you might want to take a look at another post of mine. It explains the core concepts of the Java Memory Architecture, the ones that should get you started to understand this evolution better.
String Literals in Java are stored in a String Pool. String Interning refers to a process or method by which only one copy of a specific string is stored in memory. This is done to allow the efficient usage of memory while also taking less time to retrieve, except when the string is first created. This immutable single copy of the String is called an intern. Java provides a method in the String class, intern(), to actually create/retrieve this copy of the string.
Pre-Java 7 Era (String Handling)
Prior to Java 7, Interned Strings or String Literals were stored as part of the PermGen Space. In the above article, the way to configure the non-expandable or fixed PermGen has been provided, along with a diagram of where exactly it is located in memory. The PermGen space is always fixed.
Java 7 Changes (String Handling)
So, with Java 7, Oracle engineers decided to move String Interns to the Heap. As mentioned above, this decision has to do with the following factors:
Fixed/non-expandable size of PermGen (leading to Out of Memory: PermGen Space).
String Interns are garbage collected like other Objects (based on reference count).
Set a higher number of Strings, even up to millions.
Java 8 Changes (String Handling)
The above Java 7 changes of String handling continued into Java 8. Furthermore, in Java 8, the following change was made to the memory handling related to StringInterning.
The default number of Strings in the String Pool is now 60013, as compared to 1009
At any point in time, you can check the String Interning and Pooling usage statistics in the JVM by using -XX:+PrintStringTableStatistics (Symbol Table Statistics).
Java 8 Changes (PermGen to MetaSpace)
The most impactful change to Java has been the movement from PermGen to MetaSpace. The following are the changes in Java 8:
Eliminate or reduce Out of Memory: PermGen SpaceError. (PermGen is Gone) [PermGen elimination].
Memory for Class metadata is allocated only from native memory. Earlier, it was from the Contiguous Java Heap Memory. [MetaSpace Allocation].
Virtually unlimited (or very high) memory for Class metadata from native memory. [MetaSpace Allocation].
Limit the maximum limit for metadata in native memory using -XX:MaxMetaspaceSize [MetaSpace Configuration].
Garbage collection is triggered once the MaxMetaspaceSize is reached [MetaSpace Garbage Collection].
PermGen and MetaSpace are not a direct movement. (Some items from PermGen have been moved to MetaSpace. There are some miscellaneous items moved to the Heap Space, like Interned Strings) [PermGen <> MetaSpace, Heap Space Impact].
The earlier PermGen flags are ignored, like -XX:PermSize and -XX:MaxPermSize. If used, a warning is issued saying that these flags are no longer valid in Java 8. [PermGen Compiler Flags].
Once the MaxMetaSpaceSize is reached, the Out of Memory: MetaSpace Error is thrown. [MetaSpace Error].
The default MetaSpaceSize on a 32-bit and 64-bit machines are 12MB and 16MB respectively. In contrast, the default MaxPermSize was always set to 64MB. [MetaSpace Default Size].
The native memory size can be set by -XX:MaxDirectMemorySize. (The default is 128MB) [Native Memory or Direct Buffer Size].
MetaSpace usage is available from the verbose GC log using -XX:+PrintGCDetails
PermGen had a fixed size, but MetaSpace can Auto-Tune and Auto-Increase depending on the underlying OS. [MetaSpace Size Efficiency].
Classes can be de-allocated concurrently without GC pauses. It is more efficient than in PermGen, as that required frequent GC pauses. [MetaSpace Performance].
Note: Many authors have erroneously stated that PermGen is part of the Java Heap. You have to note this fact that PermGen was/is never a part of the Java Heap. It was only allocated as part of Contiguous Memory as the Java Heap. In the case of Metaspace, such a Contiguous Allocation does not exist, Metaspace lies in or is allocated in the native memory of the operating system.
Published at DZone with permission of Sumith Puri. See the original article here.
Opinions expressed by DZone contributors are their own.