Close

Java Swing - Is it necessary to remove Listeners of an unused Component?

[Updated: Apr 27, 2018, Created: Dec 28, 2017]

This example shows that it is not necessary to remove listener of a component which is being removed from the UI. This is true even for a listener whose reference still lives externally in the active program.

Example

public class ComponentListenersAndGcTest {
    public static void main(String[] args) {
        JFrame frame = createFrame();
        JPanel componentPanel = new JPanel();
        JPanel topPanel = new JPanel();
        JButton removeAddComponentButton = new JButton("add/remove");
        removeAddComponentButton.addActionListener(e -> removeAndAddComponents(componentPanel));
        topPanel.add(removeAddComponentButton);
        frame.add(topPanel, BorderLayout.NORTH);
        frame.add(componentPanel);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static int c = 0;
    private static final ActionListener listener = (ae) -> System.out.println(ae.getActionCommand());

    private static void removeAndAddComponents(JPanel panel) {
        panel.removeAll();
        for (int i = 0; i < 10000; i++) {
            MyButton b = new MyButton(Integer.toString(++c));
            b.addActionListener(listener);
            panel.add(b);
        }
        panel.validate();
        panel.repaint();
        System.gc();
    }

    private static JFrame createFrame() {
        JFrame frame = new JFrame("Listeners GC example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(600, 300));
        return frame;
    }

    private static class MyButton extends JButton {
        public MyButton(String text) {
            super(text);
        }

        @Override
        protected void finalize() throws Throwable {
            System.out.println("button finalized: " + getText());
            System.out.println("----------");
        }
    }
}

Output

Clicking 'add/remove' button each time (except for the first time) will mark the buttons for garbage collection:

button finalized: 5
----------
button finalized: 1129
----------
button finalized: 1203
----------
button finalized: 1270
----------
button finalized: 1337
----------
button finalized: 1390
----------
button finalized: 1424
----------
button finalized: 1463
----------
button finalized: 1505
----------
button finalized: 1536
----------
button finalized: 1573
----------
button finalized: 1616
----------
button finalized: 1655
----------
button finalized: 1688
----------
button finalized: 1724
----------
button finalized: 1762
----------
button finalized: 1798
----------
button finalized: 1835
----------
button finalized: 1872
----------
button finalized: 1910
----------
button finalized: 1943
----------
button finalized: 1981
----------
button finalized: 2022
----------
button finalized: 2067
----------
button finalized: 2102
----------
button finalized: 2138
    .......

When a listener added to the button, its reference is kept within the button internally which is not a criteria for the garbage collection in case if the button is no longer used in the program. If a button's reference is kept outside actively (e.g. in a collection) then it will not be eligible for garbage collection. See also a more basic example for the garbage collection eligibility here.

Example Project

Dependencies and Technologies Used:

  • JDK 1.8
  • Maven 3.3.9

Unused Component Listener Test Select All Download
  • unused-components-gc-test
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ComponentListenersAndGcTest.java

    See Also