United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6559589 Memory leak in JScrollPane.updateUI()
JDK-6559589 : Memory leak in JScrollPane.updateUI()

Details
Type:
Bug
Submit Date:
2007-05-18
Status:
Closed
Updated Date:
2011-01-19
Project Name:
JDK
Resolved Date:
2009-05-18
Component:
client-libs
OS:
windows_xp
Sub-Component:
javax.swing
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:
6u14 (b02)

Related Reports
Backport:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)

java version "1.5.0_11"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_11-b03)
Java HotSpot(TM) Client VM (build 1.5.0_11-b03, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

Linux rh3 2.4.21-32.ELsmp #1 SMP Fri Apr 15 21:17:59 EDT 2005 i686 i686 i386 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
In default L&F (metal), each call of JScrollPane.updateUI() will make it's propertyChangeListener list grow.
The leaked class is: javax.swing.plaf.metal.MetalScrollPaneUI$1, which is created in method javax.swing.plaf.metal.MetalScrollPaneUI.createScrollBarSwapListener().

It can be reproduced with both J2SE 1.5 and 1.6, on both Windows and Linux platform.

In my opinion, the root cause should be: javax.swing.plaf.metal.MetalScrollPaneUI extends javax.swing.plaf.basic.BasicScrollPaneUI, but the method "void uninstallListeners(JScrollPane scrollPane)" in MetalScrollPaneUI does not override the method "void uninstallListeners(JComponent c)" in BasicScrollPaneUI, so the listener registered in MetalScrollPaneUI does not be unregistered when uninstallUI is called.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
It is simple to reproduce. In any Swing program, call updateUI() method of a JScrollPane object, and then check it's property change listener list with method getPropertyChangeListeners(), you will see the listener list grows each time.
In my sample source code, it also print out the class name of the listeners.



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package test;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.util.*;

public class UpdateTest extends JDialog {
  javax.swing.Timer timer;
  JButton exitBtn = new JButton();
  JScrollPane jScrollPaneTest = new JScrollPane();
  JLabel jLabelInfo = new JLabel();

  public static void main(String[] args) {
    UpdateTest dlg = new UpdateTest();
    dlg.setVisible(true);
  }

  public UpdateTest() {

    setTitle("UpdateTest");

    exitBtn.setText("exit");
    exitBtn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    });
    jLabelInfo.setText("Test JScrollPane.updateUI, please see stdout.");
    jScrollPaneTest.getViewport().add(jLabelInfo);

    getContentPane().setLayout(new BorderLayout());
    getContentPane().add(exitBtn, java.awt.BorderLayout.SOUTH);
    getContentPane().add(jScrollPaneTest, java.awt.BorderLayout.CENTER);
    pack();

    timer = new javax.swing.Timer(1000, new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JComponent toUpdate = jScrollPaneTest;

        toUpdate.updateUI();
        PropertyChangeListener[] listeners = toUpdate.getPropertyChangeListeners();

        // print it's PropertyChangeListeners after updateUI.
        System.out.println("There are " + listeners.length + " PropertyChangeListeners.");
        HashMap<String, Integer> h = new HashMap<String, Integer>();
        for (int i = 0; i < listeners.length; ++i) {
          String className = listeners[i].getClass().getName();
          int n = 1;
          if (h.containsKey(className)) {
            n = h.get(className) + 1;
          }
          h.put(className, n);
        }
        for (Iterator<Map.Entry<String, Integer>> it = h.entrySet().iterator(); it.hasNext(); ) {
          Map.Entry<String, Integer> entry = it.next();
          System.out.println("" + entry.getValue() + " listeners are " + entry.getKey());
        }
        System.out.println();
      }
    });
    timer.start();
  }
}


---------- END SOURCE ----------

                                    

Comments
EVALUATION

MetalScrollPaneUI.uninstallListeners(JScrollPane scrollPane) doesn't override the super method
and actually never get called. I agree with the submitter about the fix
                                     
2009-02-05



Hardware and Software, Engineered to Work Together