JDK-4836635 : Resource leak in JFileChooser Windows L&F
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.2,1.4.2_09
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000,windows_2003
  • CPU: x86
  • Submitted: 2003-03-24
  • Updated: 2003-05-25
  • Resolved: 2003-05-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2_12Fixed
Description
Name: ssR10077			Date: 03/24/2003

###@###.###
The following test case leaks about 1600 GDI objects. Bug is reproducible
only with Windows L&F. With Metal L&F it eats <100 GDI objects.

import java.io.*;
import java.awt.*;
import javax.swing.*;

public class Test {
    public static void main(String[] args) throws Throwable {

UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel
");
        new Test();
    }

    public Test() {
        JFrame frame = new JFrame();
        frame.setSize(500,500);
        frame.show();

        for (int i = 0; i < 20; i++) {
            JFileChooser chooser = new JFileChooser();
            frame.getContentPane().add(chooser);
            frame.validate();
            frame.repaint();
            try { Thread.sleep(10); } catch (Throwable e) {};
            frame.getContentPane().remove(chooser);
            frame.validate();
            frame.repaint();
            try { Thread.sleep(10); } catch (Throwable e) {};
            System.gc();
            System.gc();
        }
    }
}

======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b08
14-06-2004

EVALUATION I can reproduce this on Windows 2000. I'm seeing approximately the same number of leaked resources with 1.4.1 and 1.4.2 (800+). This is not a regression from 1.4.1, so committing to Tiger. ###@###.### 2003-03-24 Name: ssR10077 Date: 03/25/2003 The leak is in BasicFileChooserUI's BasicFileView, which has a HashMap of icons that are keyed by File instances and which can be Win32ShellFolder2 objects as well. It is caused by improper caching of icons due to inconsistency of equals() and hashCode() of Win32ShellFolder2. The problem is that the equal items should have the same hashCode() otherwise HashMap messes up. Which isn't true for Win32ShellFolder2 equals(). Also Win32ShellFolder2 has another resource leak with PIDL. ======================================================================
11-06-2004

SUGGESTED FIX Name: ssR10077 Date: 03/25/2003 ------- Win32ShellFolder2.java ------- *** /tmp/dOxaqmb Tue Mar 25 16:49:48 2003 --- Win32ShellFolder2.java Tue Mar 25 16:58:41 2003 *************** *** 352,362 **** return path1.equalsIgnoreCase(path2); } /** * Check to see if two ShellFolder objects are the same */ public boolean equals(Object o) { ! if (o == null || !(o instanceof Win32ShellFolder2)) { // Short-circuit circuitous delegation path if (!(o instanceof File)) { return super.equals(o); --- 352,377 ---- return path1.equalsIgnoreCase(path2); } + + public int hashCode() { + String path = getPath(); + if (path == null) { + return 0; + } + return path.toUpperCase().hashCode(); + } + /** * Check to see if two ShellFolder objects are the same */ public boolean equals(Object o) { ! if (o == null) { ! return super.equals(o); ! } ! if (hashCode() != o.hashCode()) { ! return false; ! } ! if (!(o instanceof Win32ShellFolder2)) { // Short-circuit circuitous delegation path if (!(o instanceof File)) { return super.equals(o); *************** *** 483,488 **** --- 498,504 ---- int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; do { childPIDL = getNextChild(pEnumObjects); + boolean releasePIDL=true; if (childPIDL != 0 && (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { Win32ShellFolder2 childFolder = null; *************** *** 490,501 **** && personal != null && pidlsEqual(pIShellFolder, childPIDL, personal.relativePIDL)) { childFolder = personal; - releasePIDL(childPIDL); } else { childFolder = new Win32ShellFolder2(this, childPIDL); } list.add(childFolder); } } while (childPIDL != 0); releaseEnumObjects(pEnumObjects); } --- 506,520 ---- && personal != null && pidlsEqual(pIShellFolder, childPIDL, personal.relativePIDL)) { childFolder = personal; } else { childFolder = new Win32ShellFolder2(this, childPIDL); + releasePIDL=false; } list.add(childFolder); } + if (releasePIDL) { + releasePIDL(childPIDL); + } } while (childPIDL != 0); releaseEnumObjects(pEnumObjects); } *************** *** 523,528 **** --- 542,548 ---- break; } } + releasePIDL(childPIDL); } releaseEnumObjects(pEnumObjects); return child; *************** *** 674,691 **** private Image makeIcon(long hIcon, boolean getLargeIcon) { ! if (hIcon > 0L) { // Get the bits. This has the side effect of setting the imageHash value for this object. int size = getLargeIcon ? 32 : 16; int[] iconBits = getIconBits(hIcon, size); if (iconBits != null) { ! BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); img.setRGB(0, 0, size, size, iconBits, 0, size); - return img; } disposeIcon(hIcon); } ! return null; } --- 694,711 ---- private Image makeIcon(long hIcon, boolean getLargeIcon) { ! BufferedImage img = null; ! if (hIcon > 0L) { // Get the bits. This has the side effect of setting the imageHash value for this object. int size = getLargeIcon ? 32 : 16; int[] iconBits = getIconBits(hIcon, size); if (iconBits != null) { ! img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); img.setRGB(0, 0, size, size, iconBits, 0, size); } disposeIcon(hIcon); } ! return img; } ------- Win32ShellFolderManager2.java ------- *** /tmp/dFUaWhb Tue Mar 25 14:58:33 2003 --- Win32ShellFolderManager2.java Tue Mar 25 14:57:16 2003 *************** *** 49,60 **** static Win32ShellFolder2 createShellFolderFromRelativePIDL(Win32ShellFolder2 parent, long pIDL) { // Walk down this relative pIDL, creating new nodes for each of the entries while (pIDL != 0) { long curPIDL = Win32ShellFolder2.copyFirstPIDLEntry(pIDL); if (curPIDL != 0) { parent = new Win32ShellFolder2(parent, curPIDL); - pIDL = Win32ShellFolder2.getNextPIDLEntry(pIDL); } } return parent; } --- 49,65 ---- static Win32ShellFolder2 createShellFolderFromRelativePIDL(Win32ShellFolder2 parent, long pIDL) { // Walk down this relative pIDL, creating new nodes for each of the entries + long oldPIDL = 0; while (pIDL != 0) { long curPIDL = Win32ShellFolder2.copyFirstPIDLEntry(pIDL); if (curPIDL != 0) { parent = new Win32ShellFolder2(parent, curPIDL); } + pIDL = Win32ShellFolder2.getNextPIDLEntry(pIDL); + if (oldPIDL != 0) { + Win32ShellFolder2.releasePIDL(oldPIDL); + } + oldPIDL = pIDL; } return parent; } ====================================================================== Name: ssR10077 Date: 03/25/2003 ------- ShellFolder2.cpp ------- *** /tmp/drBayqb Tue Mar 25 17:22:51 2003 --- ShellFolder2.cpp Tue Mar 25 17:22:20 2003 *************** *** 793,799 **** hres = pIcon->Extract(szBuf, index, &hIconLarge, &hIcon, (16 << 16) + 32); if (SUCCEEDED(hres)) { if (getLargeIcon) { ! hIcon = hIconLarge; } } } --- 793,802 ---- hres = pIcon->Extract(szBuf, index, &hIconLarge, &hIcon, (16 << 16) + 32); if (SUCCEEDED(hres)) { if (getLargeIcon) { ! fn_DestroyIcon((HICON)hIcon); ! hIcon = hIconLarge; ! } else { ! fn_DestroyIcon((HICON)hIconLarge); } } } ======================================================================
11-06-2004