Memory Leaks in Java
A memory leak in Java occurs when an application unintentionally holds references to objects that are no longer needed, preventing the Garbage Collector (GC) from reclaiming memory. Over time, this can lead to OutOfMemoryError and degrade application performance.
Common Causes of Memory Leaks
- Unclosed Resources – Streams, database connections, or file readers not closed properly.
- Static Field References – Holding large objects in static fields that remain in memory for the application’s lifetime.
- Inner Class or Anonymous Class References – Non-static inner classes holding a reference to their outer class, preventing it from being garbage collected.
- Incorrect Use of Collections – Storing objects in collections (e.g.,
List
,Map
) and not removing them when no longer needed. - Thread Local Variables – Using
ThreadLocal
incorrectly, leading to objects being retained for longer than expected. - Listeners and Callbacks – Not removing event listeners when they are no longer needed.
- Finalizers – Using finalizers improperly can delay garbage collection.
How to Prevent Memory Leaks
- Use Try-With-Resources
Automatically closes resources like files, sockets, and database connections.
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
Remove Unused References
Set unused object references to null
to make them eligible for GC.
myObject = null;
Use Weak References
If objects should be garbage collected when not strongly referenced, use WeakReference
or SoftReference
.
WeakReference<MyObject> weakRef = new WeakReference<>(new MyObject());
Avoid Static Collections
If using static collections, ensure proper cleanup.
static List<Data> cache = new ArrayList<>();
public static void clearCache() {
cache.clear();
}
Manually Remove Event Listeners
button.removeActionListener(listener);
Monitor with Profiling Tools
Use tools like:
- VisualVM
- Eclipse Memory Analyzer (MAT)
- YourKit
- JConsole
Properly Manage ThreadLocals
ThreadLocal<MyObject> threadLocal = new ThreadLocal<>();
threadLocal.remove();