Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8020983

OutOfMemoryError caused by non garbage collected JPEGImageWriter Instances

XMLWordPrintable

    • b02
    • b37
    • windows_7
    • Verified

        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.

              bae Andrew Brygin
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              9 Start watching this issue

                Created:
                Updated:
                Resolved: