leak
memory
java

How can I create a memory leak in Java?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

In Java, memory leaks are generally harder to create than in languages without automatic garbage collection, but they can still occur due to improper handling of objects and references. Here are some common ways to create a memory leak in Java:

1. Unintentionally Holding References (Commonly with Static Variables)

When objects are stored in static fields, they persist for the lifetime of the application, as static variables are associated with the class rather than an instance. If a large object or collection is held in a static variable and not cleared, it will stay in memory indefinitely.

java
1public class MemoryLeakExample {
2    private static List<String> list = new ArrayList<>();
3
4    public static void addToList() {
5        for (int i = 0; i < 1000; i++) {
6            list.add("String " + i);  // The list will keep growing and never be cleared
7        }
8    }
9}

In this example, every time addToList() is called, it adds items to list, but since list is static, it is never eligible for garbage collection.

2. Using Unclosed Resources (e.g., Streams, Sockets)

Failing to close resources like streams, files, or sockets can lead to memory leaks because these resources are held in memory until explicitly released.

java
1public class MemoryLeakExample {
2    public void readFile(String path) {
3        try {
4            FileInputStream fis = new FileInputStream(path);
5            // Process file
6        } catch (IOException e) {
7            e.printStackTrace();
8        } // No `finally` block, so `fis` is never closed, causing a leak
9    }
10}

Without properly closing fis, the resource may not be released, leading to a leak.

3. Inner Classes with References to Outer Classes

Non-static inner classes implicitly hold a reference to their outer class instance. If the inner class instance persists beyond the outer class's intended lifetime, it can prevent the outer class from being garbage-collected.

java
1public class OuterClass {
2    private String largeString = "Some large data...";
3
4    public class InnerClass {
5        // Inner class has an implicit reference to OuterClass
6        public void print() {
7            System.out.println(largeString);
8        }
9    }
10}

If an instance of InnerClass is kept in memory, it holds a reference to the OuterClass instance, which may prevent it from being garbage-collected.

4. Retaining References in Collections

Adding objects to collections and forgetting to remove them, especially in long-lived collections like caches or listeners, can prevent these objects from being garbage-collected.

java
1public class MemoryLeakExample {
2    private List<byte[]> cache = new ArrayList<>();
3
4    public void addToCache() {
5        for (int i = 0; i < 1000; i++) {
6            cache.add(new byte[1024 * 1024]);  // Adding 1MB objects to the cache
7        }
8    }
9}

Without any logic to remove or limit the size of cache, the application will keep growing in memory.

5. Using Finalizers

Java’s finalize() method can cause memory leaks because finalizable objects are not immediately collected. This can lead to delays in garbage collection, and excessive reliance on finalizers can cause memory leaks.

java
1public class MemoryLeakExample {
2    @Override
3    protected void finalize() throws Throwable {
4        // Custom finalizer logic
5    }
6}

Using finalize() can delay garbage collection and create memory retention issues, as objects are only collected after the finalizer queue is processed.

6. Improperly Managed Weak/Soft References

Using weak or soft references incorrectly (e.g., using a WeakHashMap but maintaining a strong reference elsewhere) can lead to memory leaks, as these references are intended to be garbage-collected when no strong references exist.

Avoiding Memory Leaks

  1. Use Static Variables Carefully: Avoid holding onto objects in static fields unless necessary.
  2. Use try-with-resources for Resource Management: Always close resources like streams and files.
  3. Limit Collection Sizes: For caches, consider using libraries like LinkedHashMap or Guava with automatic size limits.
  4. Be Mindful with Inner Classes: Use static nested classes if you don’t need a reference to the outer instance.
  5. Avoid Finalizers: Use try-with-resources or Cleaner instead of finalize().

By understanding these patterns, you can avoid creating memory leaks in Java applications.


Course illustration
Course illustration

All Rights Reserved.