How to implement explicit marking some reference as "unneeded" in Java?

78 views Asked by At

It seems to me, that I found a situation, when the standard garbage collection algorithm can't be used well.

Suppose I have some object A, which adds itself as event listener for events from object B upon construction. Since object has all required data to add itself as a listener, hence it also has data to remove itself from listeners.

Unfortunately, the removal process can't be initiated by GC, because object will be referenced in listeners list until explicitly removed.

So, this means that either object should never add itself as a listener, or there should be a way to mark some references as unimportant. In latter case GC would initiate garbage collection even if some references to the object exist -- if they are only of "unimportant" case.

Obviously, programmer should be obliged to clear all unimportant references in some method like dispose or finalize.

I understand that this direct implementation would be a security bleach. For example, if programmer violated disposing contract, garbage collection would provide incorrect references.

So, the question is: is there some library or pattern, to implement this relationship?

3

There are 3 answers

0
Rich On

If you just want your object lifetime to be managed to references to it other than as a listener then you could change your collection of listeners to be a 'Weak' collection like WeakHashMap. Such a collection uses Weak References to avoid keeping objects alive after all other references have been cleared.

0
ControlAltDel On

Check out the different subclasses of Reference in Java. I think this is what you are looking for

0
Radiodef On

In general you should make it your job to remove references when you want an object to get garbage collected. This is part of managing memory in a garbage collected environment.

Just, for example:

class MyInternalFrame extends JInternalFrame implements ActionListener {
    ...

    void removeSelfAndDispose() {
        for(JMenuItem button : parent.getMenuItems())
            button.removeActionListener(this);
        dispose();
    }
}

It is really better to avoid storing these persistent references, however. For example, use static nested classes instead of implementing a listener on a container.

It would be possible to use WeakReference to concoct a listener that does not prevent garbage collection, for example:

class MyInternalFrame extends JInternalFrame {
    ...

    MyInternalFrame() {
        for(JMenuItem button : parent.getMenuItems())
            button.addActionListener(new WeakListener(this, button));
    }

    static class WeakListener implements ActionListener {
        final Reference<JInternalFrame> ref;
        final AbstractButton button;

        WeakListener(JInternalFrame frame, AbstractButton button) {
            ref = new WeakReference<JInternalFrame>(frame);
            this.button = button;
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            JInternalFrame frame = ref.get();
            if(frame == null) {
                button.removeActionListener(this);
                return;
            }

            ...
        }
    }
}

But this is sketchy and should not be relied on. We do not have control over when garbage collection runs, so doing something like this may result in unpredictable behavior. (The object we are keeping a reference to still exists and responds to events after you think it's been removed.)

It is more reliable to simply prevent unwanted references from getting put places or deliberately remove them when it is appropriate to do so.