Duplicate :
|
Name: jk109818 Date: 01/11/2002 FULL PRODUCT VERSION : java version "1.4.0-beta3" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84) Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode) FULL OPERATING SYSTEM VERSION : Windows Millennium [Version 4.90.3000] A DESCRIPTION OF THE PROBLEM : FileSystemView.getSystemIcon is not releasing GDI resources back to Windows, which causes the system to crash after repeated invocations (even spread across different runs). I first noticed this problem in a real program, so it doesn't take an artificial testcase like this for it to occur. A few runs of a Java program which uses system icons can exhaust GDI memory and force a reboot. STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Compile and run the attached testcase on a Windows system. I'm on Windows ME, but I highly doubt that it makes a difference. The testcase will attempt to get icons for every file on your system. It frequently forces the garbage collector to run just to prove that that doesn't help. EXPECTED VERSUS ACTUAL BEHAVIOR : Expected result: Testcase prints a bunch of periods and exits normally. Actual result: After a minute or so, your system should have crashed in one of a variety of ways. I have seen everything from the program simply hanging (but due to no GDI resources you get an error message if you try to start any other programs) to shutting my system down (as in I saw, for no apparent reason, "It is now safe to turn off your computer" and then the computer turned itself off). This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import java.io.*; import javax.swing.filechooser.*; public class TestCase { static int count; private static FileSystemView fileSystemView = FileSystemView.getFileSystemView(); public static void scanDirectory(File parent) { File[] files = parent.listFiles(); if (files == null) return; for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) scanDirectory(files[i]); else { try { fileSystemView.getSystemIcon(files[i]); System.out.print("."); } catch (Exception e) { /* ignore */ } } if (++count >= 10) { count = 0; // gc and sleep just to prove finalizer doesn't help System.gc(); try { Thread.sleep(100); } catch (InterruptedException e) { } } } } public static void main(String[] arg) { File[] roots = fileSystemView.getRoots(); for (int i = 0; i < roots.length; i++) scanDirectory(roots[i]); } } ---------- END SOURCE ---------- (Review ID: 138198) ====================================================================== Name: rmT116609 Date: 01/16/2003 FULL PRODUCT VERSION : java version "1.4.1_01" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01) Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode) FULL OPERATING SYSTEM VERSION : Microsoft Windows XP [Version 5.1.2600] ADDITIONAL OPERATING SYSTEMS : All of Windows platform A DESCRIPTION OF THE PROBLEM : Win32ShellFolder.getIconBits() is not releasing GDI resources. It's copy of Bug ID 4622892. I wrote the patch of this bug to http://developer.java.sun.com/developer/bugParade/bugs/4622892.html. however there is no reaction. STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Compile and run the attached test on a Windows system. If implemented correctly, all GDI resources are released correctly. However GDI resources are not released. You can check it by TaskManager of Windows(see GDI Object). EXPECTED VERSUS ACTUAL BEHAVIOR : Expected result : print "success." at last. Actual result : print "used up GDI resources." at count 5000(on WindowsXP, in the case of Win9x, used up GDI resources at a fewer count.) REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import java.io.File; import java.io.FileNotFoundException; import java.awt.Image; import sun.awt.shell.ShellFolder; public class test{ private static int count; public static void main(String[] args){ File[] roots = File.listRoots(); count = 0; for(int i = 0; i < roots.length; i++){ try{ ShellFolder shell = ShellFolder.getShellFolder( roots[i] ); Image icon = shell.getIcon(false); System.out.println((++count) + " " + icon); if( icon == null ){ System.out.println( "used up GDI resources." ); System.exit( 1 ); } }catch( FileNotFoundException exception ){ } func(roots[i]); } System.out.println( "success." ); } private static void func(File dir){ File[] files = dir.listFiles(); if(files != null){ for(int i = 0; i < files.length; i++){ try{ ShellFolder shell = ShellFolder.getShellFolder( files[i] ); Image icon = shell.getIcon(false); System.out.println((++count)+ " " + icon); if( icon == null ){ System.out.println "used up GDI resources." ); System.exit( 1 ); } }catch( FileNotFoundException exception ){ } if(files[i].isDirectory()){ func(files[i]); } } } } } ---------- END SOURCE ---------- SUGGESTED FIX : the following is not work around. It's the debuging method of this bug. Please correct /j2se/src/win32/native/sun/windows/ShellFolder.cpp as follows JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder_getIconBits (JNIEnv* env, jobject folder, jlong hicon, jint iconSize) { // Get the icon info ICONINFO iconInfo; if (!fn_GetIconInfo((HICON)hicon, &iconInfo)) { return NULL; } // Get the screen DC HDC dc = GetDC(NULL); if (dc == NULL) { DeleteObject( iconInfo.hbmColor ); //add DeleteObject( iconInfo.hbmMask ); //add return NULL; } // Set up BITMAPINFO BITMAPINFO bmi; memset(&bmi, 0, sizeof(BITMAPINFO)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = iconSize; bmi.bmiHeader.biHeight = -iconSize; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; // Extract the color bitmap int nBits = iconSize * iconSize * 32 / 8; long colorBits[4096]; GetDIBits(dc, iconInfo.hbmColor, 0, iconSize, colorBits, &bmi, DIB_RGB_COLORS); // Extract the mask bitmap long maskBits[4096]; GetDIBits(dc, iconInfo.hbmMask, 0, iconSize, maskBits, &bmi, DIB_RGB_COLORS); // Copy the mask alphas into the color bits for (int i = 0; i < nBits; i++) { colorBits[i] = colorBits[i] | ((maskBits[i] != 0) ? 0 : 0xff000000); } // Release DC ReleaseDC(NULL, dc); // Release bitmap handle in icon info DeleteObject( iconInfo.hbmColor ); //add DeleteObject( iconInfo.hbmMask ); //add // Create java array jintArray iconBits = env->NewIntArray(nBits); // Copy values to java array env->SetIntArrayRegion(iconBits, 0, nBits, colorBits); return iconBits; } I think that fllowing is also foreget releasing the GDI resource, please correct it. JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder_getIcon__JJZ (JNIEnv* env, jobject folder, jlong parentIShellFolder, jlong relativePIDL, jboolean getLargeIcon) { IShellFolder* pParent = (IShellFolder*) parentIShellFolder; if (pParent == NULL) { return 0; } LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL; if (pidl == NULL) { return 0; } IExtractIcon* pIcon; if (pParent->GetUIObjectOf(NULL, 1, const_cast<LPCITEMIDLIST*>(&pidl), IID_IExtractIcon, NULL, (void**)&pIcon) != S_OK) { return 0; } CHAR szBuf[MAX_PATH]; INT index; UINT flags; if (pIcon->GetIconLocation( GIL_FORSHELL, szBuf, MAX_PATH, &index, &flags) != S_OK) { pIcon->Release(); return 0; } HICON hIcon; HICON hIconLarge; if (pIcon->Extract(szBuf, index, &hIconLarge, &hIcon, (16 << 16) + 32) != S_OK) { pIcon->Release(); return 0; } //return (jlong)(getLargeIcon ? hIconLarge : hIcon); pIcon->Release(); //add if (getLargeIcon){ //add DestroyIcon(hIcon); //add return (jlong)hIconLarge; //add }else{ //add DestroyIcon(hIconLarge); //add return (jlong)hIcon; //add } //add } (Review ID: 180015) ======================================================================