Where the String Pool Lives
The String pool (also called the string table or intern pool) is where the JVM keeps one shared copy of each string literal and each string passed to intern() (see "String Intern Method in Java"). A common question is where it lives. Since Java 7, the pooled String objects live on the heap, like other objects, and the pool itself is a hash table of references kept by the JVM in native memory. Before Java 7, pooled strings lived in PermGen, a small fixed area that often ran out. In this lesson, you will see the pool's statistics from a running program and learn what that design means in practice.
Where Things Are
| Part | Location |
|---|---|
The String objects that are pooled (characters and all) | The heap (since Java 7) |
| The string table: a hash table that points to them | Native memory owned by the JVM |
Literals in compiled classes ("Navika" in your code) | The class's constant pool in metaspace, resolved to pooled heap strings when first used |
| Before Java 7 | Pooled strings lived in PermGen, outside the normal heap |
Because pooled strings are ordinary heap objects, they are garbage collected like any other object once nothing refers to them.
Example: Watching the String Table Grow
Let's see an example that reads the string table's statistics from inside the program, interns 10,000 new strings, and reads them again.
import java.lang.management.ManagementFactory;
import javax.management.ObjectName;
public class PoolStats {
static long entries() throws Exception {
String stats = (String) ManagementFactory.getPlatformMBeanServer()
.invoke(new ObjectName("com.sun.management:type=DiagnosticCommand"),
"vmStringtable", new Object[] {null},
new String[] {String[].class.getName()});
for (String line : stats.split("\n")) {
if (line.startsWith("Number of entries")) {
String count = line.split(":")[1].trim().split("\\s+")[0];
return Long.parseLong(count);
}
}
return -1;
}
public static void main(String[] args) throws Exception {
long before = entries();
String[] keep = new String[10_000];
for (int i = 0; i < keep.length; i++) {
keep[i] = ("student-" + i).intern();
}
long after = entries();
System.out.println("Table grew by at least 10,000? "
+ (after - before >= 10_000));
String a = new String("Navika");
System.out.println("new String is pooled? " + (a == "Navika"));
System.out.println("after intern()? " + (a.intern() == "Navika"));
}
}Table grew by at least 10,000? true
new String is pooled? false
after intern()? trueExplanation: The program calls the JVM's VM.stringtable diagnostic (the same report jcmd <pid> VM.stringtable prints) to read the number of entries. Interning 10,000 new strings adds 10,000 entries. A String created with new is a separate heap object; intern() returns the pooled copy, the same object as the literal.
What This Means in Practice
- No more "PermGen space" errors from interning; interned strings share the normal heap.
- Heap size matters for programs that intern many strings.
- Duplicate strings can still waste heap. G1 offers
-XX:+UseStringDeduplication, which makes equalStringobjects share one character array during garbage collection, without interning.
Common Mistakes
Saying the String pool is "in the stack" or "in PermGen". It's on the heap since Java 7.
Interning every string to save memory. Interning has a cost; use it only for strings that repeat a lot.
Comparing strings with ==. Use equals; whether two strings are the same pooled object is an implementation detail.
Interview Corner
Where is the String pool stored in Java?
Since Java 7, interned String objects, including those for literals, are allocated on the regular heap and are garbage collected when unreachable. The JVM tracks them in a native hash table (the string table). Before Java 7 they lived in the permanent generation, which was small and caused OutOfMemoryError: PermGen space. Class files store literals in their constant pools, which are resolved to pooled heap strings at runtime.
Practice
- Easy: Run
jcmd <pid> VM.stringtableon a running Java program (usejpsto find its ID) and read the number of entries. - Harder: Intern 100,000 strings, drop all references to them, call
System.gc(), and check whether the number of entries goes down.
Key Takeaways
Was this tutorial helpful?