Java application is recklessly consuming memory

For a project I am working on, I was tasked with creating a way to convert an image to a non-crisis hash so that it can be easily compared to similar images, however I ran into an issue where the JVMs start recklessly consuming memory despite Java Monitoring and The Management Console does not report any increase in memory consumption.

When I first launched the application, the Task Manager will report these values: Task Manager However, after about 30 seconds, these values ​​will double or triple.

I used JMMC to dump the process, but it only reported 1.3MB usage: Eclipse MAT

The weirdest part for me is that the app does an operation that lasts about 15 seconds, then it waits for 100 seconds (debug) and it is for 100 seconds of the sleeping thread that the memory used is doubled.

Here are my two classes:

ImageHashGenerator.java

package com.arkazex.srcbot;

import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;

public class ImageHashGenerator {

    public static byte[] generateHash(Image image, int resolution) {
        //Resize the image
        Image rscaled = image.getScaledInstance(resolution, resolution, Image.SCALE_SMOOTH);
        //Convert the scaled image into a buffered image
        BufferedImage scaled = convert(rscaled);
        //Create the hash array
        byte[] hash = new byte[resolution*resolution*3];
        //Variables
        Color color;
        int index = 0;
        //Generate the hash
        for(int x = 0; x < resolution; x++) {
            for(int y = 0; y < resolution; y++) {
                //Get the color
                color = new Color(scaled.getRGB(x, y));
                //Save the colors
                hash[index++] = (byte) color.getRed();
                hash[index++] = (byte) color.getGreen();
                hash[index++] = (byte) color.getBlue();
            }
        }
        //Return the generated hash
        return hash;
    }

    //Convert Image to BufferedImage
    private static BufferedImage convert(Image img) {
        //Create a new bufferedImage
        BufferedImage image = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_3BYTE_BGR);
        //Get the graphics
        image.getGraphics().drawImage(img, 0, 0, null);
        //Return the image
        return image;
    }
}

      

Test.java

package com.arkazex.srcbot;

import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Test {

    public static void main(String[] args) throws IOException {
        //Create a hash
        byte[] hash = ImageHashGenerator.generateHash(ImageIO.read(new File("img1.JPG")), 8);    //Memory grows to around 150MB here
        System.out.println(new String(hash));
        try{ Thread.sleep(100000); } catch(Exception e) {}    //Memory grows to around 300MB here
    }
}

      

EDIT: The program stopped growing to 300MB after a few seconds for no apparent reason. I didn't change anything in the code, it just stopped doing it.

+3


source to share


2 answers


I think what you are missing is that some image classes use non-heap memory. It is (presumably) invisible to JMMC because it is only told about cumulus usage. OS level memory monitoring sees this ... because it looks at the total resource consumption of the JVM running your application.

The problem is that non-heap memory blocks are only recovered when the corresponding image objects on the heap are complete. This only happens when they collect trash.

The program stopped growing to 300MB after a few seconds for no apparent reason. I didn't change anything in the code, it just stopped doing it.



I expect the JVM decided it was time to do a full GC (or something like that) and that caused it to free up a lot of space in the non-heap memory pool. This meant that the JVM no longer needed to keep growing the pool.

(I'm deliberately vague because I don't actually know how non-heap memory allocation works under the covers in a modern JVM, but if you want to investigate, the JVM source code can be downloaded ...)

0


source


See explanation in /** comments */



public class Test {

    public static void main(String[] args) throws IOException {
        //Create a hash

        /** Here it allocates (3 * resolution^2 )bytes of memory to a byte array */
        byte[] hash = ImageHashGenerator.generateHash(ImageIO.read(new File("img1.JPG")), 8);    //Memory grows to around 150MB here

        /** And here it again allocates the same memory to a String 
        Why print a String of 150 million chars? */
        System.out.println(new String(hash));
        try{ Thread.sleep(100000); } catch(Exception e) {}    //Memory grows to around 300MB here
    }
}

      

0


source







All Articles