String Pool

String interning and memory optimization

Interview Relevant: Common interview question
6 min read

The String Pool (String Intern Pool)

The String Pool is a special memory region in the heap where Java stores string literals. It enables memory optimization by reusing immutable String objects.

How String Pool Works

  • String literals are automatically stored in the pool
  • Duplicate literals share the same reference
  • new String() creates objects outside the pool
  • intern() method adds strings to the pool

🔑 Memory Layout:

Heap Memory
├── String Pool
│   ├── "Hello" ← s1, s2 both point here
│   └── "World"
└── Regular Heap
    ├── String("Hello") ← s3 points here
    └── String("Hello") ← s4 points here

⚠️ Java 7+ Change: String Pool was moved from PermGen to Heap, making it eligible for garbage collection.

Code Examples

String Pool vs new String()

java
1// String Pool demonstration
2String s1 = "Hello";          // Created in String Pool
3String s2 = "Hello";          // Reuses same object from Pool
4String s3 = new String("Hello");  // New object in heap (NOT pool)
5String s4 = new String("Hello");  // Another new object in heap
6
7// Reference comparison
8System.out.println(s1 == s2);     // true (same pool reference)
9System.out.println(s1 == s3);     // false (pool vs heap)
10System.out.println(s3 == s4);     // false (different heap objects)
11
12// Content comparison (always true for same content)
13System.out.println(s1.equals(s2));  // true
14System.out.println(s1.equals(s3));  // true
15System.out.println(s3.equals(s4));  // true

Using intern() to add strings to pool

java
1// intern() method - Add string to pool
2String s1 = new String("Hello");  // Heap object
3String s2 = s1.intern();          // Returns pool reference
4String s3 = "Hello";              // Pool reference
5
6System.out.println(s1 == s2);     // false (heap vs pool)
7System.out.println(s2 == s3);     // true (both from pool!)
8
9// Practical use of intern()
10String dynamicString = new String("Dynamic").intern();
11String literal = "Dynamic";
12System.out.println(dynamicString == literal);  // true!
13
14// Runtime string interning
15Scanner scanner = new Scanner(System.in);
16String input = scanner.nextLine().intern();  // Add user input to pool
17
18// Use intern() when:
19// 1. You have many duplicate strings
20// 2. You want == comparison for performance
21// 3. Memory optimization is critical

Compile-time vs runtime string creation

java
1// Compile-time vs Runtime strings
2String s1 = "Hello";              // Compile-time literal → Pool
3String s2 = "Hel" + "lo";         // Compile-time constant → Pool!
4String s3 = "Hel";
5String s4 = s3 + "lo";            // Runtime concatenation → Heap!
6String s5 = s4.intern();          // Explicitly add to Pool
7
8System.out.println(s1 == s2);     // true (both from pool)
9System.out.println(s1 == s4);     // false (s4 is on heap)
10System.out.println(s1 == s5);     // true (s5 interned to pool)
11
12// final variables are compile-time constants
13final String hello = "Hello";
14final String world = "World";
15String message = hello + world;   // Optimized at compile time!
16
17String literal = "HelloWorld";
18System.out.println(message == literal);  // true!
19
20// Non-final variables prevent optimization
21String h = "Hello";
22String w = "World";
23String msg = h + w;               // Runtime concatenation
24System.out.println(msg == literal);  // false!

Memory optimization strategies

java
1// Memory optimization with String Pool
2// Scenario: Processing 1 million records with repeated values
3
4// WITHOUT interning (wasteful)
5List<String> countries = new ArrayList<>();
6for (int i = 0; i < 1_000_000; i++) {
7    // Creates new String each time!
8    countries.add(new String("USA"));
9}
10// Memory: ~1 million String objects!
11
12// WITH interning (optimized)
13List<String> countriesOptimized = new ArrayList<>();
14for (int i = 0; i < 1_000_000; i++) {
15    // All share same pool reference
16    countriesOptimized.add("USA");
17}
18// Memory: 1 String object + references
19
20// Manual interning for dynamic data
21List<String> fromDatabase = new ArrayList<>();
22for (String country : fetchCountriesFromDB()) {
23    fromDatabase.add(country.intern());  // Intern dynamic data
24}
25
26// Caution: Don't over-use intern()
27// - Interning has overhead
28// - Pool lookup takes time
29// - Only beneficial for repeated strings

Use Cases

  • Memory optimization with repeated strings
  • Fast equality checks with ==
  • Processing large datasets with duplicates
  • Configuration value caching
  • Symbol tables in compilers
  • Reducing GC pressure

Common Mistakes to Avoid

  • Relying on == for string comparison
  • Over-using intern() (has overhead)
  • Not understanding compile-time optimization
  • Assuming all strings are in the pool
  • Memory leaks from excessive interning (pre-Java 7)
  • Confusing String Pool with string caching