Where is String Pool Stored (Which Memory Area)?
String Pool is a special area where JVM stores unique strings. Its location has changed across different Java versions.
π’ Junior Level
String Pool is a special area where JVM stores unique strings. Its location has changed across different Java versions.
Brief history:
- Java 6 and earlier: PermGen (special area for metadata) β frequent
OutOfMemoryError: PermGen spaceerrors - Java 7+: Java Heap (regular heap where all objects live) β now GC can remove unused strings from the pool
Why this matters: In modern Java, String Pool is in Heap, so itβs limited by the total memory size (-Xmx), not a separate limit.
Simple analogy: PermGen β like a small safe with fixed size. Heap β like a large warehouse that can be expanded.
Practical meaning: in Java 7+ you can intern more strings without separate configuration, but now the pool competes for the same memory as your objects.
When String Pool location doesnβt matter
For 95% of applications this is academic knowledge. This knowledge matters when:
(1) mass intern(), (2) GC tuning, (3) migration between Java versions.
π‘ Middle Level
Version details
Java 6: PermGen
- PermGen β a separate memory area for class metadata
- Size is limited (
-XX:MaxPermSize, usually 64-256MB) - GC in PermGen was inefficient
- Excessive
intern()βOOM: PermGen space
Java 7 (specifically, 7u6): String Pool moved from PermGen to Java Heap.
- Moved to main heap
- String Pool shares memory with all application objects
- GC efficiently removes unreferenced strings
- Limited only by
-Xmx
Java 8+: Metaspace (NOT String Pool!)
- PermGen replaced by Metaspace (in Native Memory)
- String Pool remained in Java Heap (not in Metaspace!)
- Common misconception β thinking the pool moved to Metaspace
Practical application
// In Java 7+ you can safely intern more strings
for (String city : cities) {
city = city.intern(); // Won't cause OOM: PermGen
}
// But may cause OOM: Java heap space if heap is full
Typical mistakes
-
Mistake: Thinking String Pool is in Metaspace Solution: Pool is in Heap. Metaspace β only for class metadata
-
Mistake: Not configuring StringTableSize for mass intern() Solution:
-XX:StringTableSize=1000003
π΄ Senior Level
Internal Implementation
JVM Memory Structure (Java 8+):
JVM Memory Layout:
βββ Heap
β βββ Young Generation (Eden, S0, S1)
β βββ Old Generation
β βββ String Pool (StringTable) β HERE
βββ Metaspace (Native Memory)
β βββ Class metadata, method data
βββ Code Cache
βββ JIT compiled code
StringTable:
// OpenJDK β StringTable β native hash table in C++
class StringTable : public RehashableHashtable<oop, mtSymbol> {
// oop (ordinary object pointer) β internal JVM type for reference to Java object.
// mtSymbol β memory category in JVM (Symbol = string data).
// Stored in C++ heap, but String objects themselves β in Java Heap
};
Evolution β details of the move
Java 6 (PermGen):
- Strings in pool lived forever (or until OOM)
- GC didnβt clean PermGen efficiently
-XX:MaxPermSize=256mβ hard limit
Java 7 (move to Heap):
- JEP: moving String Table to Java Heap
- Reason: PermGen was being removed in future versions
- Strings became regular objects for GC
Java 8 (Metaspace):
- PermGen removed completely
- Metaspace β Native Memory, auto-expanding
- String Pool did not move β stayed in Heap
Architectural Trade-offs
Pool in Heap β pros:
- GC manages strings as regular objects
- No separate limit β limited by common
-Xmx - String entries without references can be GCβd
Pool in Heap β cons:
- Large number of interned strings competes for Heap with business objects
- May increase GC pause time (more objects to scan)
- G1 GC: StringTable scan adds overhead to evacuation pause
Edge Cases
-
GC and String Pool: In Java 7+ strings from pool CAN be GCβd if no strong references exist. But if you hold references β they wonβt be collected.
-
Weak References in StringTable: Some JVMs experimented with weak references for StringTable entries, but HotSpot uses strong references.
-
String Deduplication vs Pool: Deduplication (G1 GC) combines
byte[]arrays in Heap, but this is a separate mechanism from String Pool.
Performance
| Metric | PermGen (Java 6) | Heap (Java 7+) | | βββββ | βββββββββ | ββββββββ | | Max size | -XX:MaxPermSize (64-256MB) | -Xmx (GB+) | | GC efficiency | Poor | Good | | String eviction | Manual (restart) | Automatic (GC) | | OOM risk | High (PermGen space) | Medium (Java heap space) |
Production Experience
Scenario: Migrating application from Java 8 to Java 17:
- Team thought String Pool was in Metaspace
- Configured
-XX:MaxMetaspaceSize=512m, but didnβt increase-Xmx - Result:
OOM: Java heap spaceunder load - Fix: increased
-Xmxfrom 2g to 4g, pool worked correctly
Monitoring
# Check StringTable size
jcmd <pid> VM.stringtable -verbose
# Memory usage
jstat -gc <pid> 1000
# Heap dump analysis
jmap -dump:live,format=b,file=heap.hprof <pid>
# In MAT: java.lang.String β dominator tree
Best Practices for Highload
- String Pool in Heap β account for it when calculating
-Xmx - For mass
intern():-XX:StringTableSize=1000003(or larger) - Monitor via
jcmd VM.stringtable - For automatic deduplication:
-XX:+UseStringDeduplication(G1 GC)
π― Interview Cheat Sheet
Must know:
- Java 6 and below: String Pool in PermGen (fixed size, frequent OOM)
- Java 7+: String Pool moved to Java Heap (managed by GC, limited by
-Xmx) - Java 8+: Metaspace replaced PermGen, but String Pool stayed in Heap (NOT in Metaspace!)
- In Heap, GC can remove strings from pool if unreferenced
- Common misconception β thinking pool is in Metaspace
- StringTable β native hash table in C++, but String objects β in Java Heap
Frequent follow-up questions:
- Why was String Pool moved from PermGen to Heap? β PermGen was being removed, GC in PermGen was inefficient, in Heap strings became regular objects for GC.
- Can String Pool cause OOM? β Yes,
OOM: Java heap spacein Java 7+ (previouslyOOM: PermGen space). - In which memory area is String Pool in Java 17? β In Java Heap. Not in Metaspace, not in Code Cache.
- How to monitor String Pool? β
jcmd <pid> VM.stringtable -verbose.
Red flags (DONβT say):
- β βString Pool is in Metaspaceβ β most common mistake, pool is in Heap
- β βString Pool has a separate memory limitβ β limited by common
-Xmx - β βGC doesnβt clean String Poolβ β in Java 7+ can remove unreachable entries
- β βPermGen and Metaspace β the same thingβ β Metaspace is in Native Memory, PermGen was in Heap
Related topics:
- [[1. How String Pool Works]]
- [[12. Can String Pool Cause OutOfMemoryError]]
- [[3. When to Use intern()]]
- [[22. What is String Deduplication in G1 GC]]