United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-8020983 OutOfMemoryError caused by non garbage collected JPEGImageWriter Instances
JDK-8020983 : OutOfMemoryError caused by non garbage collected JPEGImageWriter Instances

Details
Type:
Bug
Submit Date:
2013-05-03
Status:
Resolved
Updated Date:
2013-08-10
Project Name:
JDK
Resolved Date:
2013-07-31
Component:
client-libs
OS:
windows_7
Sub-Component:
javax.imageio
CPU:
Priority:
P3
Resolution:
Fixed
Affected Versions:
7u21
Fixed Versions:
7u40 (b37)

Related Reports
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:

Sub Tasks

Description
FULL PRODUCT VERSION :
error with
java version  " 1.7.0_21 " 
and
java version  " 1.6.0_45 " 

No error with
java version  " 1.6.0_43 "  and prior


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
Red Hat: Linux 2.6.32-279.5.2.el6.x86_64
also reproducible on Mac OS

A DESCRIPTION OF THE PROBLEM :
When converting Images with
 " ImageWriter imageWriter = (ImageWriter) ImageIO.getImageWritersByFormatName( " jpeg " ).next(); "  You will receive an instance of JPEGImageWriter. Now call methods ?write? and ?flush? on this instance.

This image writer object will never be garbage collected. This is reproducible with java 6u45. It works fine for us until version 6_u43.

I checked also if it would work with newest Java 7 Release (Update 21) but it doesn't work neither.
Other Java 7 releases I have not tested!

Doing above description in a loop will cause the described OutOfMemoryError.
You can reproduce it with any heap sizes.
In my case I tried following
-Xms64m -Xmx128m
-Xms512m -Xmx1024m
-Xms512m -Xmx3072m
The error will always occur, but of course it takes longer as larger the heap is.

When creating a heap dump, you'll see that the number of  " living "  JPEGImageWriter instances and the number of saved images are equal

With other ImageWrtiters like  " gif "  or  " png "  the problem seems not to occur. Just the JPEGImageWriter is leaking

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
We have a complex application where one use case is to rescale images.
But I have written new sourcecode, that is much shorter than our real life application. But with the attached source code you can reproduce the problem on an easy level.

So just execute the attached java code (main method)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Exception in thread  " main "  java.lang.OutOfMemoryError: Java heap space
        at java.awt.image.DataBufferInt.<init>(Unknown Source)
        at java.awt.image.Raster.createPackedRaster(Unknown Source)
        at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
        at java.awt.image.BufferedImage.<init>(Unknown Source)
        at OomTest.getImage(OomTest.java:62)
        at OomTest.main(OomTest.java:31)
ACTUAL -
Exception in thread  " main "  java.lang.OutOfMemoryError: Java heap space
        at java.awt.image.DataBufferInt.<init>(Unknown Source)
        at java.awt.image.Raster.createPackedRaster(Unknown Source)
        at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
        at java.awt.image.BufferedImage.<init>(Unknown Source)
        at OomTest.getImage(OomTest.java:62)
        at OomTest.main(OomTest.java:31)

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread  " main "  java.lang.OutOfMemoryError: Java heap space
        at java.awt.image.DataBufferInt.<init>(Unknown Source)
        at java.awt.image.Raster.createPackedRaster(Unknown Source)
        at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
        at java.awt.image.BufferedImage.<init>(Unknown Source)
        at OomTest.getImage(OomTest.java:62)
        at OomTest.main(OomTest.java:31)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;

public class OomTest {

  /**
   * The main method. Run it with  " little "  heap size (e.g java -Xms32m -Xmx64m OomTest) You will see it works fine
   * until jvm version 6_43, but crashes with 6_45 for {@link OutOfMemoryError} Also with bigger heap spaces it
   * crashes.
   *
   * When analyzing the heap dumps yo'll see that there are the same instances of ImageWriter as rounds run before
   * OutOfMemoryError occurred.
   *
   * @param args the arguments
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public static void main(String[] args) throws IOException {

    BufferedImage image;

    File file = new File( " output.jpg " );

    for (int i = 1; i < 1000; i++) {
      log( " read " , i);
      image = getImage();

      log( " getWriter " , i);
      ImageWriter imageWriter = (ImageWriter) ImageIO.getImageWritersByFormatName( " jpeg " ).next();

      ImageOutputStream ios = null;
      try {
        ios = ImageIO.createImageOutputStream(file);
        imageWriter.setOutput(ios);
        log( " write " , i);
        imageWriter.write(image);
        ios.flush();
      } finally {
        if (ios != null)
          ios.close();
      }
      System.out.println( " Congratulations: No OutOfMemoryError occurred. " );
    }
  }

  private static void log(String message, int repeat) {
    System.out.println(message +  "  round  "  + repeat);
    System.out.println( " totalMemory: "  + Runtime.getRuntime().totalMemory() / 1024 / 1024 +  " MB " );
    System.out.println( " maxMemory: "  + Runtime.getRuntime().maxMemory() / 1024 / 1024 +  " MB " );
    System.out.println( " freeMemory: "  + Runtime.getRuntime().freeMemory() / 1024 / 1024 +  " MB " );

  }

  private static BufferedImage getImage() {
    int width = 2500;
    int height = new Random().nextInt(2500) + 1;
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

    Graphics2D ig2 = image.createGraphics();
    ig2.fillRect(0, 0, width - 1, height - 1);

    return image;
  }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Stay on Java 6_43 not moving on, what is not acceptable.
                                    

Comments
SQE is OK to take this
                                     
2013-07-31
URL:   http://hg.openjdk.java.net/jdk7u/jdk7u40-dev/jdk/rev/46b203b37e06
User:  bae
Date:  2013-07-31 20:04:52 +0000

                                     
2013-07-31
URL:   http://hg.openjdk.java.net/jdk7u/jdk7u40/jdk/rev/46b203b37e06
User:  lana
Date:  2013-08-01 23:43:23 +0000

                                     
2013-08-01
Moved the CPU13_04 critical watch label from backport bug to main.
                                     
2013-08-06
SQE ok to take the fix in 5u55.
                                     
2013-08-10



Hardware and Software, Engineered to Work Together