Explain Codes LogoExplain Codes Logo

How can I create a memory leak in Java?

java
memory-leaks
resource-management
threadlocals
Alex KataevbyAlex Kataev·Sep 2, 2024
TLDR

How about an infinite loop churning out objects? These objects get placed into a static HashSet and are never garbage collected, much like the socks that seem to disappear forever in your laundry:

static Collection<Object> leakyObjects = new HashSet<>(); public void createLeak() { while (true) { leakyObjects.add(new Object()); } }

With this, you get a progressive expansion of your heap memory like a balloon ready to pop!

Inappropriately managing resources.

Ever come back from vacation and find you left the tap running? Well, unreleased resources such as unclosed IO streams lurking around your code can spark similar peril:

public void readBigData(String fileName) { FileInputStream fis = null; try { fis = new FileInputStream(fileName); // Reads file like a voracious bookworm! } finally { if (fis != null) { fis.close(); // Shutting off the tap! } } }

Not closing the FileInputStream means the buffered data hangs around your memory like unwanted guests at a party.

The Pandora's box of ThreadLocals.

Another ThreadLocal misadventure is in not managing memory usage properly, especially in cases of thread pooling (multithreading, anyone?):

private static final ThreadLocal<HeavyObject> leakyThreadLocal = new ThreadLocal<>(); public void run() { leakyThreadLocal.set(new HeavyObject()); // Do your thing... leakyThreadLocal.remove(); // Make sure to clean up after partying! }

Forget to call remove() after using ThreadLocal and you've opened Pandora's box to a spate of memory leaks.

Fallen HashSet Heroes – hashCode() and equals().

An incorrectly implemented hashCode() and equals() can cause your application to behave like a prima donna, particularly when used with hashed collections:

class BadKey { // Not-so-good equals and hashCode implementation // ... } Map<BadKey, Object> leakyMap = new HashMap<>(); leakyMap.put(new BadKey(), new Object()); // They just broke up, but the objects won't let go

JNI: Not just another acronym.

JNI or Java Native Interface allows interaction with native applications. Here's to those brave souls who have traversed this pathway, but here be dragons!

public class NativeResourceHandler { private long nativeResourceId; public NativeResourceHandler() { nativeResourceId = acquireNativeResource(); } public void close() { releaseNativeResource(nativeResourceId); // Memory released on time, unlike your paychecks } private native long acquireNativeResource(); private native void releaseNativeResource(long resourceId); }

JNI-related memory leaks can occur if you're not conscientious about managing your resources, making it a sneaky culprit.

WeakHashMap: Not as weak as you might think!

WeakHashMap allows keys to be collected, but not if the Key objects still have a strong reference somewhere:

Map<WeakReference<Key>, Object> weakMemoryHole = new WeakHashMap<>(); Key strongKey = new Key(); weakMemoryHole.put(new WeakReference<>(strongKey), new Object());

Be a good listener.

Now, when dealing with listeners, memory leaks can occur if they are added but not removed. It's like sending an invitation without providing an event end time!

class EventSource { ListenersList listeners = new ArrayList<>(); public void addListener(ListenerClass listener) { listeners.add(listener); // Think of listeners as excited party-goers } public void removeListener(ListenerClass listener) { listeners.remove(listener); // After the party, you want your peace and quiet } }

Listeners stay listening even after the party's over – unless you have the courtesy to show them the exit door!