Java应用程序不顾一切地消耗内存

时间:2015-06-07 01:47:31

标签: java memory memory-management memory-leaks

对于我正在进行的项目,我的任务是创建一种将图像转换为非加密哈希的方法,以便可以轻松地与类似的图像进行比较,但是我遇到了JVM开始的问题。尽管Java Monitoring& amp;管理控制台未报告内存消耗的任何增加。

当我第一次运行应用程序时,任务管理器会报告如下值: Task Manager 然而,仅仅约30秒后,这些值就会增加一倍或三倍。

我使用JMMC来创建进程的转储,但它只报告了大约1.3MB的使用情况: Eclipse MAT

对我来说最奇怪的部分是应用程序执行的操作持续约15秒,然后等待100秒(调试),并且在线程休眠的100秒期间,使用的内存会翻倍。

以下是我的两个课程:

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
    }
}

编辑:几秒钟后程序停止增长到300MB,没有明显的原因。我没有改变代码中的任何内容,它只是停止了它。

2 个答案:

答案 0 :(得分:0)

请参阅/** 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
    }
}

答案 1 :(得分:0)

我认为你在这里缺少的是一些图像类使用堆外内存。这是(推测)JMMC不可见的,因为它只被告知堆上使用情况。操作系统级内存使用情况监视会看到它...因为它正在查看运行应用程序的JVM的总资源消耗。

问题是只有在完成相应的堆上图像对象时才会回收堆外内存块。只有当它们被垃圾收集时才会发生。

  

几秒钟后程序停止增长到300MB,没有明显的原因。我没有改变代码中的任何内容,它只是停止了它。

我希望JVM决定是时候做一个完整的GC(或类似的东西),这会导致它释放掉堆内存池中的大量空间。这意味着JVM不再需要继续增长池。

(我故意模糊,因为我实际上并不知道现代JVM中的堆外内存分配是如何工作的。但是如果你想调查,可以下载JVM源代码...... )