How to Detect and Fix Java Memory Leaks: Real‑World Examples and Best Practices
This tutorial explains what Java memory leaks are, why they happen despite garbage collection, shows common leak patterns such as static fields, unclosed resources, improper equals/hashCode, inner classes, finalize, constant strings and ThreadLocal, and provides practical detection and prevention techniques.
1. Introduction
One of Java's core strengths is its built‑in garbage collector (GC) that automatically manages memory, but GC is not a silver bullet; memory leaks can still occur and eventually exhaust heap space.
2. What Is a Memory Leak?
A memory leak happens when objects that are no longer used remain reachable in the heap, preventing the GC from reclaiming them. Leaks waste memory, degrade performance, and can cause java.lang.OutOfMemoryError.
3. Common Java Memory‑Leak Sources
3.1 Static Fields
Static variables live as long as the application does. Storing large collections in static fields can keep them in memory forever.
public class StaticTest {
public static List<Double> list = new ArrayList<>();
public void populateList() {
for (int i = 0; i < 10_000_000; i++) {
list.add(Math.random());
}
}
public static void main(String[] args) {
new StaticTest().populateList();
}
}3.2 Unclosed Resources
Failing to close streams, database connections, or sessions leaves them allocated, preventing GC and possibly triggering OutOfMemoryError. Always close resources in a finally block or use try‑with‑resources.
3.3 Incorrect equals() / hashCode() Implementations
When objects are used as keys in HashMap or stored in HashSet, failing to override equals and hashCode correctly can cause duplicate entries to accumulate.
public class Person {
private String name;
public Person(String name) { this.name = name; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person p = (Person) o;
return name.equals(p.name);
}
@Override
public int hashCode() { return 31 * 17 + name.hashCode(); }
}3.4 Non‑static Inner Classes
Non‑static inner classes hold an implicit reference to their outer instance, preventing the outer object from being collected even after it goes out of scope. Declaring the inner class as static removes this hidden reference.
3.5 Overridden finalize()
Objects with a custom finalize method are placed on a finalizer queue and are not reclaimed immediately, which can delay GC and cause leaks. Avoid using finalizers.
3.6 Constant Strings
Calling String.intern() on large strings in Java 6 and earlier stores them in the PermGen space, which never gets reclaimed until the JVM exits. Upgrade to Java 7+ or avoid interning large strings.
3.7 ThreadLocal
ThreadLocal variables retain a reference to their values for the lifetime of the thread. In thread‑pooled environments (e.g., servlet containers), failing to call remove() can keep objects alive after the request finishes.
4. Additional Leak‑Mitigation Strategies
4.1 Profiling Tools
Use profilers (VisualVM, JProfiler, YourKit, etc.) to monitor heap usage, identify hot allocation paths, and locate leaked objects.
4.2 Detailed GC Logging
Enable verbose GC flags (e.g., -verbose:gc -XX:+PrintGCDetails) to see when collections occur and how much memory is reclaimed.
4.3 Reference Objects
Java's java.lang.ref package (SoftReference, WeakReference, PhantomReference) can be used to hold caches that allow the GC to reclaim entries when memory is low.
4.4 IDE Warnings
Eclipse (JDK 1.5+) can flag obvious leak patterns; regularly check the Problems view for such warnings.
4.5 Benchmarking
Micro‑benchmarks help compare alternative implementations and choose the most memory‑efficient approach.
4.6 Code Review
Manual reviews often catch simple mistakes—unused static collections, missing close() calls, or forgotten ThreadLocal.remove() —that automated tools miss.
5. Conclusion
Memory leaks degrade performance and can crash Java applications. There is no single cure; they arise from many patterns. By following best practices, using profiling tools, and performing regular code reviews, you can dramatically reduce the risk of leaks.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
