Question 11 Β· Section 12

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.

Language versions: English Russian Ukrainian

🟒 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 space errors
  • 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

  1. Mistake: Thinking String Pool is in Metaspace Solution: Pool is in Heap. Metaspace β€” only for class metadata

  2. 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

  1. 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.

  2. Weak References in StringTable: Some JVMs experimented with weak references for StringTable entries, but HotSpot uses strong references.

  3. 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 space under load
  • Fix: increased -Xmx from 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 space in Java 7+ (previously OOM: 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]]