✅ 1. Introduction
The String object is one of the most commonly used classes in the Java programming language.
In this article, we’ll explore the String Constant Pool (or String Pool)— a special memory region where the JVM stores String literals to optimize memory usage and performance.
✅ Why String Pool Is Important
- ➤ Memory Efficiency
- Prevents duplicate string objects.
- Saves memory by reusing existing strings.
- ➤ Performance Optimization
- String comparison using
==
works for string literals since they reference the same object.
- String comparison using
- ➤ Immutable Design Enables Pooling
- Since strings are immutable, sharing the same object across the application is safe.
✅ 2. String Interning
Because Strings in Java are immutable, the JVM can save memory by storing only one copy of each string literal in a special area called the String Pool. This process is called interning.
When we create a String variable and assign a value using a literal, the JVM first checks the String Pool to see if the same string already exists.
- If it exists, the JVM returns a reference to the existing string without creating a new object.
- If it doesn’t exist, the new string is added to the pool, and its reference is returned.
Let’s see a simple example to understand how this works.
✔️ Example:
public class StringInterningExample {
public static void main(String[] args) {
String str1 = "Java Knowledge Base";
String str2 = "Java Knowledge Base";
System.out.println(str1 == str2); // Output: true
}
}
👉 Both str1
and str2
point to the same object in the String Pool.

✅ 3. Strings Allocated Using the Constructor
When we create a String using the new
operator, the JVM always creates a new object in the heap, separate from the String Pool.
✔️ Example:
public class NewStringExample {
public static void main(String[] args) {
String literalString = "Java Knowledge Base";
String constructedString = new String("Java Knowledge Base");
System.out.println(literalString == constructedString); // Output: false
}
}
👉 Explanation:
literalString
points to the interned string in the pool.constructedString
points to a new object in heap memory.
✅ 4. String Literal vs String Object
When we create a String using the new()
operator, a new object is always created in heap memory. But when we use a String literal like "Java Knowledge Base"
, the JVM checks the String Pool first — if the string already exists, it reuses it; otherwise, it adds the new string to the pool for future use.
Creation Type | Location in Memory | Reuses Existing Object? |
---|---|---|
String Literal | String constant Pool | Yes |
new String() | Heap Memory | No |
✔️ Example Comparison:
public class StringComparisonExample {
public static void main(String[] args) {
String first = "Java Knowledge Base";
String second = "Java Knowledge Base";
System.out.println(first == second); // Output: true
String third = new String("Java Knowledge Base");
String fourth = new String("Java Knowledge Base");
System.out.println(third == fourth); // Output: false
String fifth = "Java Knowledge Base";
String sixth = new String("Java Knowledge Base");
System.out.println(fifth == sixth); // Output: false
}
}
👉 Conclusion:
Prefer using string literals for better performance and memory usage.
✅ 5. Manual Interning
We can manually add a String to the Java String Pool by using the intern()
method.
When we intern a String, its reference is stored in the pool, and the JVM will use this reference whenever the same string is needed.
Let’s see a simple example to understand this.
✔️ Example:
public class ManualInternExample {
public static void main(String[] args) {
String constantString = "interned Java Knowledge Base";
String newString = new String("interned Java Knowledge Base");
System.out.println(constantString == newString); // Output: false
String internedString = newString.intern();
System.out.println(constantString == internedString); // Output: true
}
}
👉 Manual interning ensures the string reference points to the pool object.
✅ 6. Garbage Collection
Before Java 7, the String Pool was stored in the PermGen space, which has a fixed size and cannot grow during program execution. It also could not be garbage collected.
This meant that if we interned too many strings, we could get an OutOfMemoryError.
From Java 7 onwards, the String Pool is stored in the Heap memory, which can be garbage collected.
This allows unused strings to be removed, reducing the chance of running out of memor
👉 Benefit:
Reduces the risk of OutOfMemoryError when interning many strings.
✅ 7. Performance and Optimizations
In Java 6, the only way to optimize the String Pool was by increasing the PermGen space using the JVM option:
-XX:MaxPermSize=1G
From Java 7 onwards, we have better ways to manage and view the String Pool.
Here are two useful JVM options to see the String Pool details:
-XX:+PrintFlagsFinal
-XX:+PrintStringTableStatistics
If we want to increase the pool size (number of buckets), we can use this option:
-XX:StringTableSize=4901
Before Java 7u40, the default pool size was 1009 buckets.
From Java 7u40 to Java 11, the default size was 60013 buckets, and in newer versions, it increased to 65536 buckets.
👉 Keep in mind:
Increasing the pool size uses more memory but makes inserting strings into the pool faster.
💡 Note:
- Until Java 8, Strings were stored as a
char[]
using UTF-16 encoding, where each character used 2 bytes of memory.- From Java 9 onwards, Java introduced Compact Strings.
Depending on the content, it uses eitherbyte[]
orchar[]
internally.- This helps save heap memory and reduces the work of the Garbage Collector, making Java programs more efficient.
🎯Conclusion
- In this guide, we explored how the JVM optimizes memory for String objects using the String Pool and Interning, and why immutability is a core part of the design.
- By leveraging string literals and the intern() method, we can improve both performance and memory efficiency in Java applications.