In Java, memory is divided into two main areas: Heap Memory and Stack Memory. Understanding their characteristics is crucial for efficient memory management.
1. Heap Memory
- Purpose: Used for storing objects and class-level variables (fields of a class).
- Lifetime: The objects live in the heap until they are no longer referenced, at which point the Garbage Collector removes them.
- Access: Objects in the heap are accessible globally.
- Size: Larger in size compared to the stack.
- Example: Objects created with the
newkeyword are stored in the heap.
Characteristics:
- Managed by the Garbage Collector.
- Slower access compared to stack memory due to its global nature.
- Shared across all threads in a Java application.
2. Stack Memory
- Purpose: Stores method-specific variables, primitives, and references to objects in the heap.
- Lifetime: Variables stored in the stack are removed automatically when the method ends.
- Access: Limited to the method in which the variable was declared.
- Size: Smaller compared to the heap.
- Example: Local variables and method calls are stored here.
Characteristics:
- Managed by the program (not the Garbage Collector).
- Faster access compared to heap memory.
- Thread-specific; each thread has its own stack.
Heap vs Stack Memory
| Feature | Heap Memory | Stack Memory |
|---|---|---|
| Stores | Objects and class-level variables | Method-level variables, references |
| Lifetime | Until no references exist (Garbage Collector) | Until method execution completes |
| Access Speed | Slower | Faster |
| Size | Larger | Smaller |
| Thread Access | Shared across threads | Thread-specific |
String Memory and Reassignment
In Java, Strings are immutable and managed differently in memory. They are stored in two areas:
- String Pool (part of the heap)
- Heap Memory (outside the string pool)
1. String Pool
- A special memory area inside the heap for storing interned strings.
- When a string literal is created, the JVM checks the pool first:
- If the string exists, it reuses the reference.
- If not, a new string is added to the pool.
Example:
String s1 = "Hello"; // Stored in the string pool
String s2 = "Hello"; // Reuses the reference from the pool
System.out.println(s1 == s2); // Output: true (same reference)
2. Heap Memory
- Strings created using the
newkeyword are stored in the heap (not the pool). - Even if the content matches an existing string in the pool, a new object is created.
Example:
String s1 = new String("Hello"); // New object in the heap
String s2 = new String("Hello"); // Another new object in the heap
System.out.println(s1 == s2); // Output: false (different references)
String Reassignment and Immutability
Reassignment
When a string is reassigned, it does not modify the original string but creates a new string in memory. The original string remains unchanged.
Example:
String s1 = "Hello";
s1 = "World"; // "Hello" remains in the pool; "World" is a new reference
Immutability
- Strings are immutable, meaning their content cannot be changed once created.
- Any operation that appears to modify a string (e.g., concatenation) creates a new string object.
Memory Management for Strings
- Garbage Collector:
- Unused string objects are removed when there are no references to them.
- Strings in the pool are managed by the JVM and stay as long as the program runs.
- Best Practices:
- Use string literals to benefit from the string pool.
- Use
StringBuilderorStringBufferfor frequent string manipulations to avoid creating multiple objects.
Example of Heap, Stack, and String Memory
public class MemoryExample {
public static void main(String[] args) {
int x = 10; // Stored in Stack
String s1 = "Hello"; // Stored in String Pool
String s2 = new String("World"); // Stored in Heap (outside the pool)
String s3 = "Hello"; // Reuses reference from String Pool
// Reassignment
s1 = s1 + " World"; // New String created in Heap
}
}
Java String Memory Notes
Summary Table:
Scenario Memory Location Notes int x = 10;
Stack Primitive value String s1 = "Hello";
String Pool Literal string new String("World") Heap Explicit new object String s3 = "Hello";
String Pool Reuses existing pooled string s1 = s1 + " World";
Heap Concatenation creates a new string at runtime (s1 + " World").intern(); String Pool Explicitly interns runtime string
Primitive Types and Stack Memory:
Variables like int x = 10; are stored in the stack memory.
Primitive data types in Java do not involve heap or string pool.
String Literals and the String Pool:
When you create a string like String s1 = "Hello";, the string literal "Hello" is stored in the String Pool.
If another variable is assigned the same literal (e.g., String s3 = "Hello";), it reuses the reference from the pool.
Using new String(...):
String s2 = new String("World"); creates a new object in the heap, even if the literal "World" already exists in the pool.
This results in two separate objects:
One in the pool ("World")
One in the heap (the new String object)
Runtime Concatenation and the Heap:
Expressions like s1 = s1 + " World"; are evaluated at runtime.
This uses StringBuilder behind the scenes: s1 = new StringBuilder(s1).append(" World").toString();
The result is a new String object stored in the heap, not the pool.
Even though " World" is a literal and resides in the pool, the final concatenated string (e.g., "Hello World") is created on the heap.
Interning Strings:
If you want to move a runtime-created string to the pool, use: s1 = (s1 + " World").intern();
This ensures the resulting string is either reused from the pool or added to it if not already present.
Conclusion
- Heap: Stores objects, shared globally, managed by the Garbage Collector.
- Stack: Stores method-local variables and references, thread-specific, faster access.
- Strings:
- String literals are stored in the string pool for memory efficiency.
- Strings are immutable, and any modification creates a new object.
- Use
StringBuilderfor better performance in string manipulation.