JDK-7166379 : javax.imageio.ImageIO.read(ImageInputStream) leaks file handlers
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.imageio
  • Affected Version: 7,7u4
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux_ubuntu,os_x
  • CPU: x86
  • Submitted: 2012-05-04
  • Updated: 2018-11-30
  • Resolved: 2012-06-27
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.
JDK 7 JDK 8
7u6Fixed 8 b45Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Mac OS X 10.7.3

EXTRA RELEVANT SYSTEM CONFIGURATION :
Single threaded command line app. Nothing special.

A DESCRIPTION OF THE PROBLEM :
On JDK 1.7, repeated usage of ImageIO.read(ImageInputStream) results in ���Too many open files��� exception.

Also of interest is the process contains about 10,000 POSIX Semaphores at the same time.

Attempting to close the ImageInputStream manually throws an exception that it is already closed.

JDK 1.6.0_31 does not have this issue.

More details: http://stackoverflow.com/q/10441276/43217

REGRESSION.  Last worked in version 6u31

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Repeatedly reading images via ImageIO.read(ImageInputStream) will result in exhaustion of the process's available open file descriptors.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The JavaDocs state that ImageIO.read(ImageInputStream) closes input stream unless null is returned:

http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#read(javax.imageio.stream.ImageInputStream)

ACTUAL -
FileNotFoundException: "Too many open files"

Over 10,000 POSIX Semaphores in the process:

COMMAND   PID USER   FD     TYPE DEVICE  SIZE/OFF     NODE NAME
                                      ...
java    36809  smm *235r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *236r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *237r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *238r  PSXSEM              0t0          kcms00008FC901624000
java    36809  smm *239r  PSXSEM              0t0          kcms00008FC901624000

ERROR MESSAGES/STACK TRACES THAT OCCUR :
FileNotFoundException: "Too many open files"

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// Repeatedly executing this code produces it for me.

BufferedImage image = null;
ImageInputStream stream = null;
try {
    stream = new FileImageInputStream(file);
    image = ImageIO.read(stream);

} catch (Exception ex) {
    log.error("Image could not be read: "+file.getPath());

} finally {
    // ImageIO closes input stream unless null is returned
    // http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#read(javax.imageio.stream.ImageInputStream)
    if (stream != null && image == null) {
        try {
            stream.close();
        } catch (IOException ex) {
            log.error("ERROR closing image input stream: "+ex.getMessage(), ex);
        }
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
// I expected the results to be the same as executing this code (which works fine):

BufferedImage image = null;
InputStream stream = null;
try {
    stream = new FileInputStream(file);
    image = ImageIO.read(stream);

} catch (Exception ex) {
    log.error("Image could not be read: "+file);

} finally {
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException ex) {
            log.error("ERROR closing image input stream: "+ex.getMessage(), ex);
        }
    }
}

Comments
EVALUATION This fix reports a leak of file handlers on macosx. It mentioned two ways to leak handlers: via ImageIO.read(ImageInputStream), and via semaphores. I do not observe the first leak: we explicitly close input stream if we found an appropriate reader, and this is enough (at least on 1.7.4) to release file handles. However, in case of semaphores we leak tons of handles: we perform color conversion for each line of jpeg image, and each time we create a semaphore (because we see 2 or more CPU installed on the system), then we reduce number of separate tasks down to 1 (because we have single scan line to process) and due to this never unlink the semaphore. The same problem is present on Linux systems, but in less degree because we occupy single file handle per named semaphore, whereas on macosx we always occupy new file handle. Suggested fix just postpones the creation of named semaphore until we clarify the number of separate tasks, so, now we do not create semaphores for image reading and simple color conversions (like ColorSpace.toRGB()). Beside this, now we use pSem pointer as a trigger for the semaphore destruction.
14-06-2012

SUGGESTED FIX http://sa.sfbay.sun.com/projects/java2d_data/8/7166379/
14-06-2012