Welcome back! In our previous lesson, we established the core principle of String immutability and saw how it enables the JVM to use a String Constant Pool for memory optimization. We also got a first look at the intern() method for interacting with this pool.
Today, we will build directly on that foundation to explore one of the most classic and important topics in Java: the precise difference in memory allocation when you create a String using a literal versus using the new keyword. Understanding this distinction is fundamental not just for writing memory-efficient code, but also for correctly predicting program behavior, especially when comparing objects.
By the end of this lesson, you will be able to clearly differentiate between String Constant Pool allocation for literals and heap allocation for new String() objects, tracing exactly where and how many objects are created in each case.
The Two Paths of String Creation
As we've touched upon, Java provides two primary ways to create a String object:
- Using a String Literal:
String s1 = "Java"; - Using the
newKeyword:String s2 = new String("Java");
At first glance, these seem to accomplish the same thing. However, under the hood, the JVM treats them very differently. This difference is rooted in the interplay between the main Heap memory and the specialized String Constant Pool (SCP) that resides within it.
Let's start with a simple visual model.

This diagram captures the core idea. Now, let's break down the rules that govern this behavior.
Path 1: String Literals and the String Constant Pool
When the JVM's class loader processes your code and encounters a string literal like "Java", it follows a simple, efficient procedure:
- It checks the String Constant Pool to see if a
Stringobject with the exact same sequence of characters ("Java") already exists. - If it exists: The JVM does nothing more. The reference variable (
s1in our example) is simply assigned the memory address of the existing object in the pool. - If it does not exist: The JVM creates a new
Stringobject for "Java", places it into the SCP, and then assigns the reference variable the address of this new pooled object.
The result is that for any given string value, only one object ever exists in the SCP. All literal declarations referencing that value will point to that single, canonical instance.
Consider this code:
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // This will print "true"
The reason s1 == s2 evaluates to true is that s1 and s2 are reference variables holding the exact same memory address. They both point to the one and only "hello" object inside the String Constant Pool.
Path 2: The new Keyword and Explicit Heap Allocation
Using new String("Java") tells the JVM something entirely different. The new keyword is an explicit instruction to always create a new object.
Here's the sequence of events:
- The
newoperator allocates memory for a brand newStringobject on the main heap. This object is separate and distinct from any object in the SCP, even if it has the same content. - The string literal used as the constructor argument (e.g.,
"Java") is also processed. The JVM ensures this literal exists in the SCP, following the rules from Path 1 (creating it if absent, otherwise doing nothing). - The reference variable (
s2in our initial example) is assigned the memory address of the new object on the heap.
This means that a single line like String s2 = new String("Java"); can result in two objects being involved: one in the heap (the new object) and one in the SCP (the literal). If the literal was already in the pool, then only one new object is created (on the heap).
Let's see the practical result:
String s3 = new String("hello");
String s4 = "hello";
System.out.println(s3 == s4); // This will print "false"
System.out.println(s3.equals(s4)); // This will print "true"
Here, s3 == s4 is false because s3 points to an object on the heap, while s4 points to a different object in the SCP. They have different memory addresses. However, their contents are identical, so .equals() returns true.
The following article provides a very clear, step-by-step breakdown of these scenarios with helpful diagrams.
Understanding Java String Constant Pool: Concepts, Mechanisms ...
This article from Medium provides excellent, diagram-supported explanations of how string creation impacts memory allocation.
Please read from the beginning down to the end of the second major example. Focus on these parts: The section How Strings are Created introduces the three main ways, including literals, new, and intern(). The section on How the Pool Works summarizes the mechanism. Finally, study the detailed example under Literal and new String(), which includes diagrams showing the distinct memory locations for each object.
Visualizing a Complete Example
Let's consolidate this with a slightly more complex scenario, perfectly illustrated by the diagram below.

Tracing the diagram:
String name1 = "Deepak";: The literal "Deepak" is not in the SCP, so it's created there.name1points to it.String name2 = "Deepak";: The literal "Deepak" is now in the SCP, soname2simply points to the existing object.name1 == name2istrue.String name3 = new String("Amit");: A new object "Amit" is created on the heap, andname3points to it. The literal "Amit" is also placed in the SCP (since it wasn't there before).String name4 = new String("Amit");: Another new object "Amit" is created on the heap, andname4points to it. The literal "Amit" is already in the SCP, so no new SCP object is created.name3 == name4isfalse.
For a dynamic walkthrough of this process, the following video is highly effective.
OCJA(1Z0 - 808) || String Objects Creation Heap and String Constant Pool (SCP) Part - 1
This video from Durga Software Solutions provides a methodical, whiteboard-style trace of how objects are created in both the heap and the SCP for a similar code example.
Please watch the detailed analysis from this section. The instructor carefully explains the outcome of each line of code, clarifying how many objects are created, where they are located, and which references point to them. This will help solidify the rules we've discussed.
A Deeper Look: Where is the String Pool?
Given your interest in JVM internals, a natural next question is: where exactly in memory does the String Constant Pool live? The answer has changed across Java versions, a detail that's crucial for understanding performance tuning and reading older technical articles.
- Java 6 and earlier: The SCP was located in a special part of the heap called the Permanent Generation (PermGen). This was a fixed-size area primarily used for storing class metadata and pooled strings. A major downside was that if an application interned too many strings, it could exhaust this fixed space and cause an
OutOfMemoryError: PermGen space, crashing the application. - Java 7: In a significant architectural change, the SCP was moved from PermGen into the main heap. This meant that pooled strings now lived alongside all other application objects. They could benefit from the more advanced garbage collection algorithms and the pool size was no longer fixed, but could grow and shrink with the rest of the heap.
- Java 8 and later: The entire PermGen was removed and replaced by a different area called Metaspace (which holds class metadata). The String Constant Pool, however, remains in the main heap, continuing the design from Java 7.
This evolution is why you must be careful when reading older documentation. Advice and behavior related to PermGen are no longer applicable to modern JVMs.
Where does Java's String constant pool live, the heap or the stack? - Stack Overflow
This highly-rated Stack Overflow discussion gives a concise and accurate history of the SCP's location within the JVM.
To understand this evolution, please read the following key answers: Start with the answer from 'assylias', which quotes the official Java 7 release notes about the change. Read the paragraph describing the move from PermGen to the main heap. Next, read the clear, rule-based explanation in Stephen C's answer. It succinctly states the difference: the simple rules for object creation and the pool's location. Finally, read the answer by 'Nirav' for a more detailed look at the practical implications of this move. Focus on the sections titled "String.intern() in Java 6" and "String.intern() in Java 7".
Conclusion
In this lesson, we have dissected the two distinct ways Java creates String objects and how they map to different memory areas. This is a cornerstone concept for any serious Java developer.
Key Takeaways:
- String Literals (
"..."): The JVM uses the String Constant Pool to ensure only one instance of a given string literal exists. This is highly memory-efficient. All literal references with the same content point to the same object. new String(...): This syntax forces the creation of a newStringobject on the heap every time. It is generally inefficient and should be avoided unless you explicitly require a distinct object identity.- Object Count:
String s = "text";creates at most one object (in the SCP).String s = new String("text");creates at least one object (on the heap) and potentially a second (the literal in the SCP). - Comparison: Always use
.equals()to compare string content. Use==only when you need to check if two variables refer to the exact same object in memory. - SCP Location: In modern Java (7+), the String Constant Pool resides in the main heap, allowing it to be garbage collected and sized dynamically along with other objects.
In our next session, we'll shift our focus to the mutable alternatives to String: StringBuilder and StringBuffer. You'll learn why they are essential for performance when you need to construct or modify strings frequently, and how they work internally to avoid the overhead of creating many intermediate String objects.