Fundamentals 15 min read

Unlocking Java’s String Pool: How String.intern() Saves Memory and Boosts Performance

This article explains Java’s constant pool architecture, the role of the String pool across JDK versions, demonstrates how String.intern() works with code examples, and shows how interning can dramatically reduce memory usage while also highlighting potential pitfalls.

Programmer DD
Programmer DD
Programmer DD
Unlocking Java’s String Pool: How String.intern() Saves Memory and Boosts Performance

0. Background

In Java there are eight primitive types and the special String type. To improve speed and memory, the JVM provides a constant pool, a cache at the system level.

The primitive types share a coordinated constant pool, while the String constant pool is special. There are two main ways to use it:

String literals declared with double quotes are stored directly in the constant pool.

For non‑literal strings you can call String.intern() to look up the pool and add the string if absent.

1. Constant Pool

1.1 What is the constant pool?

The JVM constant pool consists of the class file constant pool, the runtime constant pool, the global string pool, and the primitive wrapper object pool.

1.1.0 Method Area

The method area stores class structure information; object type information resides here, while instance data lives on the heap.

1.1.1 Class File Constant Pool

A .class file is a binary stream that contains a constant pool storing two kinds of constants: literals and symbolic references.

Literals include text strings, final static fields, and for primitive types only the descriptor and name are kept.

Text strings such as "abc".

final fields (static, instance, or local) like public final static int F = 0x101;.

For primitive variables only the descriptor and name are stored, not the literal value.

Symbolic references include fully qualified class names, field names and descriptors, and method names with descriptors.

Class and interface names in internal form, e.g., java/lang/String.

Field names and descriptors.

Method names and descriptors (parameter types + return type).

1.1.2 Runtime Constant Pool

When a class is loaded, its class file constant pool is copied into the runtime constant pool, which is part of the method area. During the resolution phase, symbolic references are replaced by direct references, and the StringTable is consulted to ensure consistency.

The runtime constant pool is dynamic; new constants can be added at execution time, most commonly via String.intern().

1.1.3 String Constant Pool

Before JDK 7 the string pool resided in the permanent generation; from JDK 7 onward it moved to the heap. The pool is implemented by StringTable, a shared hash table (default size 1009).

In JDK 6 the table length is fixed, leading to hash collisions and performance degradation when many strings are interned. JDK 7 allows the size to be configured.

Design goals:

Reduce allocation cost of strings.

Improve JVM performance and lower memory overhead.

Maintain a unique instance for each distinct string.

2. String.intern() and the String Pool

/** 
 * Returns a canonical representation for the string object.
 * ...
 * @return a string that has the same contents as this string, but
 *         guaranteed to be from a pool of unique strings.
 */
public native String intern();

The location of the string pool changes with JDK versions. In JDK 6 it is in the permanent generation, in JDK 7 it is in the heap, and in JDK 8 the permanent generation is replaced by Metaspace.

Example demonstrating version differences:

@Test
public void test() {
    String s = new String("2");
    s.intern();
    String s2 = "2";
    System.out.println(s == s2);

    String s3 = new String("3") + new String("3");
    s3.intern();
    String s4 = "33";
    System.out.println(s3 == s4);
}
// JDK6 output: false false
// JDK7 output: false true

Explanation for JDK 6:

Creating new String("2") produces two objects: a heap StringObject and a literal “2” in the pool. s.intern() finds the existing “2” and returns its address. String s2 = "2" reuses the literal, so s == s2 is false.

For “33”, s3.intern() creates a new pool entry, so s3 == s4 is false.

Explanation for JDK 7:

After s.intern() the literal “2” already exists, so s == s2 remains false.

When s3.intern() is called, the newly created “33” object is placed into the pool, so s3 == s4 becomes true.

3. Applications of String.intern()

When many strings are read and assigned, using String.intern() can dramatically reduce memory consumption.

static final int MAX = 1000 * 10000;
static final String[] arr = new String[MAX];

public static void main(String[] args) throws Exception {
    Integer[] DB_DATA = new Integer[10];
    Random random = new Random(10 * 10000);
    for (int i = 0; i < DB_DATA.length; i++) {
        DB_DATA[i] = random.nextInt();
    }
    long t = System.currentTimeMillis();
    for (int i = 0; i < MAX; i++) {
        // arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length]));
        arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])).intern();
    }
    System.out.println((System.currentTimeMillis() - t) + "ms");
    System.gc();
}

Running with -Xmx2g -Xms2g -Xmn1500M, the version without intern() creates about 10 million strings occupying ~640 MB, while the interned version creates only 1 345 strings using ~133 KB, demonstrating a memory saving of roughly one hundred thousand times.

Because strings are immutable, the pool guarantees uniqueness, which can be leveraged for locking resources (e.g., using a city name string as a lock). However, indiscriminate interning, such as interning every JSON key in fastjson, can overload the pool.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJVMConstant PoolString.intern
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.