From Effective Java 2/e by Joshua Bloch
Garbage-collected language can easily lead to the impression that you don’t have to think about memory management, but this isn’t quite true.
Unintentional Object Retention Example
// Can you spot the "memory leak"? public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); // memory leak return elements[--size]; // fix memory leak // Object result = elements[size]; // elements[size] = null; // return result; } /** * Ensure space for at least one more element, roughly * doubling the capacity each time the array needs to grow. */ private void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } }
- Common source of memory leak
- Cache
- Listeners and Callbacks
- Use WeakReference to avoid memory leak
- Typically discovered by
- careful code inspection
- aid of a debugging tool known as a "Heap Profiler"
// http://www.javalobby.org/java/forums/t19468.html // @author Santhosh Kumar T - santhosh@in.fiorano.com public class WeakPropertyChangeListener implements PropertyChangeListener{ WeakReference listenerRef; Object src; public WeakPropertyChangeListener(PropertyChangeListener listener, Object src){ listenerRef = new WeakReference(listener); this.src = src; } public void propertyChange(PropertyChangeEvent evt){ PropertyChangeListener listener = (PropertyChangeListener)listenerRef.get(); if(listener==null){ removeListener(); }else listener.propertyChange(evt); } private void removeListener(){ try{ Method method = src.getClass().getMethod("removePropertyChangeListener" , new Class[] {PropertyChangeListener.class}); method.invoke(src, new Object[]{ this }); } catch(Exception e){ e.printStackTrace(); } } }