Java Observer/Observable caveat
April 23rd, 2010
No comments
ProActive Virtual Machine Management is a project in which I am invested. In several places we needed to use the Java Observer/Observable pattern but weren’t really satisfied by the way Observers are saved, this way can leads to important memory leaks in APIs where the end user doesn’t not explicitly release objects. Indeed, all listeners are not garbagge collected just because they are in the listener list.
To avoid memory leaks, we wrote our own Observer/Obserable feature based on WeakReference. Here is the code:
NotifierAdapter class is the equivalent of Observable
public class NotifierAdapter implements Notifier { private ArrayList<WeakReference<NotifierListener<N, T>>> listeners = new ArrayList<WeakReference<NotifierListener<N, T>>>(); private N notifier; protected NotifierAdapter() { this.notifier = (N) this; } public NotifierAdapter(N notifier) { this.notifier = notifier; } public void addNotifierListener(NotifierListener<N, T> listener) { WeakReference<NotifierListener<N, T>> weakListenerReference = new WeakReference<NotifierListener<N, T>>(listener); this.listeners.add(weakListenerReference); } public void removeNotifierListener(NotifierListener<N, T> listener) { for (int i = 0; i < this.listeners.size(); i++) { WeakReference<NotifierListener<N, T>> weakListenerReference = this.listeners.get(i); NotifierListener<N, T> weakListener = weakListenerReference.get(); if ((weakListener == null) || (weakListener == listener)) { this.listeners.remove(weakListenerReference); } } } public void fire(T event) { ArrayList<WeakReference<NotifierListener<N, T>>> toDelete = new ArrayList<WeakReference<NotifierListener<N, T>>>(); for (WeakReference<NotifierListener<N, T>> weakListenerReference : listeners) { NotifierListener<N, T> weakListener = weakListenerReference.get(); if (weakListener == null) { toDelete.add(weakListenerReference); } else { weakListener.update(this.notifier, event); } } listeners.removeAll(toDelete); } }
The equivalent of the Observer interface: NotifierListener
public interface NotifierListener { public void update(N notifier, T event); }
And the Notifier interface
public interface Notifier { public void addNotifierListener(NotifierListener listener); public void removeNotifierListener(NotifierListener listener); public void fire(T event); }
Categories:
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 32768 bytes) in /mnt/159/sdb/d/e/jeanmichel.guillaume/wp-content/plugins/sitepress-multilingual-cms/sitepress.class.php on line 1991
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 32768 bytes) in /mnt/159/sdb/d/e/jeanmichel.guillaume/wp-content/plugins/sitepress-multilingual-cms/sitepress.class.php on line 1991