Java Memory Management
Java manages memory for objects and for the work each thread performs. We create and use objects, while the JVM tracks their storage and decides when unused objects can be collected. This reduces manual memory work, but we still need to avoid keeping objects longer than necessary.
Values, Objects, and References
A primitive variable holds a value such as 12 or true. A reference variable can refer to an object or contain null. Two references can point to the same object. Changing one reference does not change the other reference.
class Person {
String name;
}
public class HelloWorld {
public static void main(String[] args) {
Person first = new Person();
first.name = "Mira";
Person second = first;
first = null;
System.out.println(second.name);
}
}Output:
MiraThe Person object is still reachable through second. Assigning null to first does not destroy the object.
Heap Memory
The heap is the JVM runtime area from which objects and arrays are allocated. Instance fields are part of their objects. The heap is shared by threads, so access to shared mutable objects may need synchronization.
Thread Stacks
Each JVM thread has its own stack of method-call frames. A frame contains local variables and information needed to continue the call. When a method returns, its frame is removed. An object referenced by a local variable may still be reachable elsewhere after that call returns.
Do not use the rule "primitives always live on the stack and references always live on the heap." A primitive can be an object field, and a reference can be a local variable. The JVM may also optimize allocations while keeping the required program behavior.
Method Metadata and Metaspace
The JVM specification defines a method area for class-level information. In HotSpot, much class metadata is stored in native memory called Metaspace. Metaspace is not a second heap for normal application objects. Exact memory layout is an implementation detail rather than a rule every JVM must copy.
Garbage Collection
Garbage collection reclaims memory from objects that are no longer reachable in the way the collector considers live. Active threads, static fields, and other JVM roots can keep objects reachable. A cycle of objects is not enough to prevent collection if the whole cycle is unreachable.
Calling System.gc() is a request, not a promise that collection happens immediately. There is no reliable program output that proves the exact moment an ordinary object will be collected.
Example: Stop Keeping Old Results
import java.util.ArrayList;
import java.util.List;
public class HelloWorld {
public static void main(String[] args) {
List<String> recentNames = new ArrayList<>();
recentNames.add("Mira");
recentNames.add("Ravi");
System.out.println(recentNames.size());
recentNames.clear();
System.out.println(recentNames.size());
}
}Output:
2
0clear() removes the list's references to its elements. The list itself remains usable, and its backing storage may remain allocated. These string literals may also remain reachable through other references; this example does not claim they are collected.
Memory Leaks in Java
A Java application can run out of memory even with a garbage collector. For example, a static list that keeps every request result forever retains those results. Other common causes include caches without limits and listeners that are registered but never removed.
Memory and External Resources
A file handle or database connection is not just ordinary heap storage. Close resources when finished rather than waiting for garbage collection. Use try-with-resources for AutoCloseable resources. Do not depend on finalizers; finalization is deprecated for removal and does not provide timely cleanup.
OutOfMemoryError and StackOverflowError
OutOfMemoryError means the JVM cannot satisfy a memory request in some required area. Increasing heap size may help a capacity problem but does not repair unlimited retention. StackOverflowError often follows too many nested calls, such as recursion that never reaches its stopping condition.
First Steps When Investigating Memory Use
Check how memory changes over time, not just one reading. Look for growing collections and caches. Compare heap data or recordings to find which paths retain objects. Consider tools such as Java Flight Recorder, JDK Mission Control, and heap analysis tools. Avoid guessing from the number of objects created alone.
Easy Way to Remember
- A reference can keep an object reachable.
- A method returning does not necessarily make all its objects unreachable.
- The garbage collector chooses when to reclaim unused object memory.
- Close files and connections explicitly, and keep caches and collections bounded.
See you in next page....🙂