简体   繁体   中英

Memory leak in java ImageIO.read()

I am utilizing ImageIO.read(). The class which is called by the main method of the original App is this:

import java.awt.*;
import javax.swing.*;
import java.io.File;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import javax.swing.JPanel;

class ImageGenerator extends JPanel{

JpegReader jpeg;

public ImageGenerator(Aplicacion a){
    jpeg = new JpegReader();
    loadImage();

}


private void loadImage(){
    String path = "C:\\image.jpg";
    image = new BufferedImage(100,100, BufferedImage.TYPE_INT_RGB); //in case error
    try{
        image = jpeg.readImage(new File(path));
    }catch(Exception e){
        System.err.println(e.getMessage());
    }
}
public void paint(Graphics g){

    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g2.drawImage(image, 0, 0, 1000, 800, null);
}

}

I am using the above in conjunction with this other class JpegReader, which I actually found on StackOverflow as an answer, but I forgot the name of the author to quote him.

import java.awt.image.BufferedImage;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.awt.color.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.ArrayList;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.common.byteSources.ByteSourceFile;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.formats.jpeg.JpegImageParser;
import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
public class JpegReader {

public static final int COLOR_TYPE_RGB = 1;
public static final int COLOR_TYPE_CMYK = 2;
public static final int COLOR_TYPE_YCCK = 3;

private int colorType = COLOR_TYPE_RGB;
private boolean hasAdobeMarker = false;

public BufferedImage readImage(File file) throws IOException, ImageReadException {
    colorType = COLOR_TYPE_RGB;
    hasAdobeMarker = false;

    ImageInputStream stream = ImageIO.createImageInputStream(file);
    Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
    while (iter.hasNext()) {
        ImageReader reader = iter.next();
        reader.setInput(stream);

        BufferedImage image;
        ICC_Profile profile = null;
        try {
            image = reader.read(0);
        } catch (IIOException e) {
            System.out.println("Hello");
            colorType = COLOR_TYPE_CMYK;
            checkAdobeMarker(file);
            profile = Sanselan.getICCProfile(file);

            WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
            if (colorType == COLOR_TYPE_YCCK)
                convertYcckToCmyk(raster);
            if (hasAdobeMarker)
                convertInvertedColors(raster);
            image = convertCmykToRgb(raster, profile);
            System.out.println("Hello");
        }finally {
            try {
                System.out.println("facebook");
                stream.close();
            } catch (IOException ioex) {
                //omitted.
            }
        }

        return image;
    }

    return null;
}

public void checkAdobeMarker(File file) throws IOException, ImageReadException {
    JpegImageParser parser = new JpegImageParser();
    ByteSource byteSource = new ByteSourceFile(file);
    @SuppressWarnings("rawtypes")
    ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
    if (segments != null && segments.size() >= 1) {
        UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
        byte[] data = app14Segment.bytes;
        if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
        {
            hasAdobeMarker = true;
            int transform = app14Segment.bytes[11] & 0xff;
            if (transform == 2)
                colorType = COLOR_TYPE_YCCK;
        }
    }
}

public static void convertYcckToCmyk(WritableRaster raster) {
    int height = raster.getHeight();
    int width = raster.getWidth();
    int stride = width * 4;
    int[] pixelRow = new int[stride];
    for (int h = 0; h < height; h++) {
        raster.getPixels(0, h, width, 1, pixelRow);

        for (int x = 0; x < stride; x += 4) {
            int y = pixelRow[x];
            int cb = pixelRow[x + 1];
            int cr = pixelRow[x + 2];

            int c = (int) (y + 1.402 * cr - 178.956);
            int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
            y = (int) (y + 1.772 * cb - 226.316);

            if (c < 0) c = 0; else if (c > 255) c = 255;
            if (m < 0) m = 0; else if (m > 255) m = 255;
            if (y < 0) y = 0; else if (y > 255) y = 255;

            pixelRow[x] = 255 - c;
            pixelRow[x + 1] = 255 - m;
            pixelRow[x + 2] = 255 - y;
        }

        raster.setPixels(0, h, width, 1, pixelRow);
    }
}

public static void convertInvertedColors(WritableRaster raster) {
    int height = raster.getHeight();
    int width = raster.getWidth();
    int stride = width * 4;
    int[] pixelRow = new int[stride];
    for (int h = 0; h < height; h++) {
        raster.getPixels(0, h, width, 1, pixelRow);
        for (int x = 0; x < stride; x++)
            pixelRow[x] = 255 - pixelRow[x];
        raster.setPixels(0, h, width, 1, pixelRow);
    }
}

public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
    if (cmykProfile == null)
        cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("/ISOcoated_v2_300_eci.icc"));

    if (cmykProfile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) {
        byte[] profileData = cmykProfile.getData();

        if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) {
            intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first

            cmykProfile = ICC_Profile.getInstance(profileData);
        }
    }

    ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
    BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
    WritableRaster rgbRaster = rgbImage.getRaster();
    ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
    ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
    cmykToRgb.filter(cmykRaster, rgbRaster);
    return rgbImage;
}
static void intToBigEndian(int value, byte[] array, int index) {
    array[index]   = (byte) (value >> 24);
    array[index+1] = (byte) (value >> 16);
    array[index+2] = (byte) (value >>  8);
    array[index+3] = (byte) (value);
}
}

I am using sanselan-0.97-incubator.jar.

If I run this program 31 times approximately, I will get a java heap space error, so I suspect I have a memory leak.

Please help me find the memory leak or suggest how to fix the issue.

Also let me know if the jar file I'm using is OKAY, or maybe it's outdated. I had some issues locating a sanselan jar file.

Thanks in advance.

I have got the same memory issue with this code (JPEGReader). After a few trials, I found that calling reader.dispose() can solve this issue.

I give the method that I have modified. Hope it is helpful to you.

public BufferedImage readImage(File file) throws IOException, ImageReadException {
    colorType = COLOR_TYPE_RGB;
    hasAdobeMarker = false;

    ImageInputStream stream = ImageIO.createImageInputStream(file);
    try{
        Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
        while (iter.hasNext()) {
            ImageReader reader = iter.next();
            reader.setInput(stream);

            BufferedImage image;
            ICC_Profile profile = null;
            try {
                image = reader.read(0);
            } catch (IIOException e) {
                colorType = COLOR_TYPE_CMYK;
                checkAdobeMarker(file);
                profile = Sanselan.getICCProfile(file);
                WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
                if (colorType == COLOR_TYPE_YCCK)
                    convertYcckToCmyk(raster);
                if (hasAdobeMarker)
                    convertInvertedColors(raster);
                image = convertCmykToRgb(raster, profile);
                return image;
            }
            finally {
                reader.dispose();
            }
        }
        return null;
    }
    finally {
        if (stream != null){
            stream.close();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM