How String Pool Works
In a typical Java application, strings make up 25-40% of all objects. Without the pool, each copy of "Hello" would create a separate object, even if the text is completely ident...
🟢 Junior Level
String Pool is a special mechanism in JVM that stores only one copy of each unique string. This helps save memory.
In a typical Java application, strings make up 25-40% of all objects. Without the pool, each copy of "Hello" would create a separate object, even if the text is completely identical.
When you create a string via a literal, JVM checks whether such a string already exists in the pool. If yes — it returns a reference to the existing object. If no — it creates a new one and adds it to the pool.
Example:
String s1 = "Hello";
String s2 = "Hello";
// s1 and s2 — this is the same object in memory!
System.out.println(s1 == s2); // true
Why this is needed: If every string were created as a separate object, the application would consume much more memory, especially if identical strings appear frequently.
When to use: Use string literals (String s = "value";) by default — JVM will place them in the pool automatically.
🟡 Middle Level
How it works
String Pool is implemented as a StringTable hash table inside JVM. When a class is loaded, all string literals from the class’s Constant Pool are automatically placed into the String Pool.
Constant Pool — a table in the .class file containing all literals, method names, and other class constants.
Two ways a string enters the pool:
- Literals — automatically when class loads:
String s = "Hello"; - intern() method — manually at runtime:
String s = new String("Hello").intern();
Practical application
String s1 = "Java"; // Literal → immediately in pool
String s2 = new String("Java"); // new → new object in heap (NOT in pool)
String s3 = s2.intern(); // intern() → returns reference from pool to s1
System.out.println(s1 == s2); // false (different objects)
System.out.println(s1 == s3); // true (same object in pool)
Typical mistakes
-
Mistake: Using
new String("literal")without need Solution: Use literals —String s = "literal"; -
Mistake: Comparing strings via
==instead ofequals()Solution: Always useequals()for content comparison
Approach comparison
| Approach | In pool? | Creates object? | When to use |
| ——————– | —————— | ——————– | —————————————- |
| Literal "Hello" | Yes | Only if not in pool | 99% of cases |
| new String("Hello")| No (literal — yes) | Always new | Practically never |
| s.intern() | Yes | Only if not in pool | When working with huge amounts of duplicates |
🔴 Senior Level
Internal Implementation
String Pool is a native StringTable hash table with open addressing (method chaining). Keys and values are references to java.lang.String objects.
// Simplified structure from OpenJDK
class StringTable : public RehashableHashtable<oop, mtSymbol> {
// oop — pointer to Java object
// Uses hashing via String::hash_code
};
Key JVM parameters:
-XX:StringTableSize=N— hash table size (default 60013 in Java 8+, previously 1009)- Starting from JDK 11 (JEP 341), StringTable supports dynamic resizing when load factor is exceeded, similar to HashMap.
String Pool Memory Evolution
| Java Version | Location | Problems |
|---|---|---|
| Java 6 and below | PermGen | Fixed size, frequent OOM: PermGen space |
| Java 7+ | Java Heap | Managed by GC, limited only by -Xmx |
| Java 8+ (Metaspace) | Java Heap (not Metaspace!) | Can still cause OOM: Java heap space |
Common misconception: String Pool is in Metaspace. This is incorrect — it remained in Heap.
Architectural Trade-offs
Mass intern() usage:
Pros:
- Drastic RAM reduction for duplicate strings
- Fewer objects → fewer GC pauses
Cons:
intern()is a native call with hash computation and table lookup- With large number of strings, contention on global StringTable
- If
StringTableSizeis small → long collision chains → O(n) degradation
Edge Cases
-
StringTable collisions: If number of strings » StringTableSize, search degrades from O(1) to O(n). Check:
jcmd <pid> VM.stringtable -verbose -
String Pool and GC: In Java 7+, pooled strings can be GC’d if unreferenced. But if you hold references — they will never be collected.
-
Compact Strings (Java 9+): Don’t directly affect pool mechanism, but save 50% memory for Latin strings within the pool.
Performance
- Lookup in empty pool: ~nanoseconds
- Lookup in pool with 1M strings (proper StringTableSize): ~tens of nanoseconds
- Lookup in pool with 1M strings (small StringTableSize): microseconds (collisions!)
Production Experience
When loading millions of records from DB (e.g., 1M users with country field), where only 200 unique countries exist:
- Without
intern(): 1M String objects → ~48MB - With
intern(): 200 objects in pool + 1M references → ~5MB - But: CPU overhead on each
intern()call can be 10-50%
Monitoring
# StringTable statistics
jcmd <pid> VM.stringtable -verbose
# Analysis via JOL
System.out.println(GraphLayout.parseInstance(stringTable).toFootprint());
Best Practices for Highload
- Increase
-XX:StringTableSizeto a prime number > expected unique string count - Don’t use
intern()for short-lived strings (they’ll die in Young Gen anyway) - Consider
-XX:+UseStringDeduplication(G1 GC) as a transparent alternative
🎯 Interview Cheat Sheet
Must know:
- String Pool — hash table (
StringTable) in JVM, stores one copy of each unique string - Literals automatically enter the pool on class load
new String("...")creates a separate object in heap, NOT in poolintern()adds string to pool and returns reference from pool- In Java 7+ String Pool is in Java Heap (not in PermGen/Metaspace!)
-XX:StringTableSize— hash table size (default 60013 in Java 8+)- With StringTable collisions, search degrades from O(1) to O(n)
- Compact Strings (Java 9+) save 50% memory for Latin-1 strings in pool
Frequent follow-up questions:
- Where is String Pool located? — In Java Heap (since Java 7). Common mistake — answering Metaspace.
- How does a string enter the pool? — Via literals (automatically) or
intern()call (manually). - Can a string be removed from the pool? — Yes, in Java 7+ GC can collect pool entries if unreferenced.
- What happens with
new String("Hello").intern()? — An object is created in Heap, thenintern()finds"Hello"in pool and returns the pool reference. The Heap object becomes garbage.
Red flags (DON’T say):
- ❌ “String Pool is in Metaspace” — incorrect, it’s in Heap
- ❌ “
==always works for strings” — only works for literals/interned strings - ❌ “
intern()is free” — it’s a native call with CPU overhead - ❌ “String Pool has a fixed size” — it’s limited only by
-Xmxin Java 7+
Related topics:
- [[2. Difference Between Creating String via Literal and via new]]
- [[3. When to Use intern()]]
- [[11. Where is String Pool Stored (Which Memory Area)]]
- [[12. Can String Pool Cause OutOfMemoryError]]
- [[22. What is String Deduplication in G1 GC]]