destructor needed

J

Jacob

I have objects that are added as listeners
to various system events (such as change of
language or units etc.).

To subscribe to such events I typically call
someManager.addListener(this); and the "this"
object will be added in a subscription list
of someManager.

My problem is when these objects are no longer
needed. Normally they would be GC'd, but because
of the subscription references they are not,
and the memory is in effect lost.

My current approach is to have a destroy()
method on these objects where I unsubscribe
to system events (removeListener). I am then
forced to think C++ and figure out when the
object actually dies and call the destroy()
method there, which is a pain as it may
include calling destroy() of children objects
etc. and in general it will be very hard to
get rid of them all.

As I assume my architechture is commonplace,
some of you might have a brigther solution
to the problem?

Thanks!
 
S

Sergio Juan

Hi.

Look at java.lang.ref.WeakReference at the Java API documentation. I think
it is what you are looking for, anyway I can not help you more as I never
had to work with it.

HTH
 
F

Filip Larsen

Jacob wrote
I have objects that are added as listeners
to various system events (such as change of
language or units etc.).

To subscribe to such events I typically call
someManager.addListener(this); and the "this"
object will be added in a subscription list
of someManager.

My problem is when these objects are no longer
needed. Normally they would be GC'd, but because
of the subscription references they are not,
and the memory is in effect lost.

As Sergio Juan already suggested, you can use java.lang.WeakReference to
solve this problem.

A simple way of doing this is to code a weak listener that holds a weak
reference to the real listener and insert the weak listener instead. It goes
like this:

// this is the normal listener interface
public interface MyListener extends EventListener {
void myAction(EventObject ev);
}

// this is the class producing the events
public class MyEventSource {
public void addMyListener(MyListener l) { ... }
public void removeMyListener(MyListener l) { ... }
}

// this is the new class you need
public class WeakMyListener implements MyListener {

final private WeakReference ref;

public WeakMyListener(MyListener delegate) {
this.ref = new WeakReference(delegate);
}

public void myAction(EventObject ev) {
MyListener delegate = (MyListener) ref.get();
if (delegate != null) {
delegate.myAction(ev);
} else {
MyEventSource source = (MyEventSource) ev.getSource();
source.removeMyListener(this);
}
}
}

With this you can add the listener with

source.addMyListener(new WeakMyListener(myListener));

If you want to manually remove the listener before it is garbage collected,
you have to store a reference to the weak listener and remove that instead.
Don't store any references to myListener or it might never be garbage
collected. If you have trouble figuring out where to use weak references,
make an object diagram (include the main thread in that diagram) that show
the relevant object references in your system, and then figure out which
references must be weak in order for the "branch" be garbage collected.
Usually a branch only needs a single weak reference to allow a whole block
to be garbage collected. If you overdo it and introduce too many weak
references you run the risk of "premature" garbage collection, so be sure
that you know what you are doing.

Note that the above approach only works if the source object is actually
emitting events. If it is not emitting event and you keep adding weak
listeners, they will all just pile up in the listener list just as before.
In this case you may have to use a ReferenceQueue or make the source emit
some kind of "keep-alive" events.

If the MySource is not a fixed class or interface (with add and remove for
the listener type), or in other words, if you cannot generally do the cast
in "(MyEventSource) ev.getSource()", you may have to use another approach to
remove the weak listener from the list, like using reflection. However, if
at all possible, I would strongly recommend that you at least use an
interface for the add and remove method so you can cast directly.


Regards,
 
J

John C. Bollinger

Jacob said:
I have objects that are added as listeners
to various system events (such as change of
language or units etc.).

To subscribe to such events I typically call
someManager.addListener(this); and the "this"
object will be added in a subscription list
of someManager.

My problem is when these objects are no longer
needed. Normally they would be GC'd, but because
of the subscription references they are not,
and the memory is in effect lost.

My current approach is to have a destroy()
method on these objects where I unsubscribe
to system events (removeListener). I am then
forced to think C++ and figure out when the
object actually dies and call the destroy()
method there, which is a pain as it may
include calling destroy() of children objects
etc. and in general it will be very hard to
get rid of them all.

As I assume my architechture is commonplace,
some of you might have a brigther solution
to the problem?

I think your architecture sounds strange, and could perhaps benefit from
a redesign. A more typical design would feature

(1) Listeners that are added and never need to be removed (normal for
many GUIs)

and/or

(2) Listeners for which it is clear when and to what they should be
added, and when and from what they should be removed. It is rare that
you cannot bracket the code that requires the listener(s) with matching
add and removeListener calls, preferrably in the same method but
possibly in different methods invoked at the same call depth. try /
finally is definately your friend if you need to ensure resource cleanup.


Where the actual listener addition and removal logic goes depends on the
specific requirements of your application. A hierarchical invocation of
destroy / close methods, should it be necessary, oughtn't to be too
difficult to achieve. Design your classes with that in mind if it's
what you need.


John Bollinger
(e-mail address removed)
 
D

David Holliday

Java has a pre defined weak reference map (forget what it is called) that I
have used for this problem. Though a map is not what I would normally
choose, it worked fine.

-David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top