Java应用程序不计后果地消耗内存

Java应用程序不计后果地消耗内存,java,memory,memory-management,memory-leaks,Java,Memory,Memory Management,Memory Leaks,对于我正在进行的一个项目,我的任务是创建一种将图像转换为非加密哈希的方法,以便可以轻松地将其与类似的图像进行比较,但是我遇到了一个问题,JVM将开始不计后果地消耗内存,尽管Java监视和管理控制台没有报告内存消耗的任何增加 当我第一次运行应用程序时,任务管理器会报告如下值: 然而,仅仅30秒后,这些值就会翻倍或三倍 我使用JMMC创建了一个进程转储,但它只报告了大约130万的使用量: 对我来说,最奇怪的是,应用程序执行一个大约持续15秒的操作,然后等待100秒(调试),在线程睡眠的100秒期间

对于我正在进行的一个项目,我的任务是创建一种将图像转换为非加密哈希的方法,以便可以轻松地将其与类似的图像进行比较,但是我遇到了一个问题,JVM将开始不计后果地消耗内存,尽管Java监视和管理控制台没有报告内存消耗的任何增加

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

我使用JMMC创建了一个进程转储,但它只报告了大约130万的使用量:

对我来说,最奇怪的是,应用程序执行一个大约持续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;
    }
}

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

请参阅
/**注释中的说明*/

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

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

问题在于,堆外内存块只有在相应的堆内映像对象最终确定后才能回收。只有当它们被垃圾收集时才会发生这种情况

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

我希望JVM决定是时候执行完整的GC(或类似的操作)了,这会导致JVM在堆外内存池中释放大量空间。这意味着JVM不再需要继续增长池


(我故意含糊其辞,因为我不知道堆外内存分配在现代JVM中是如何工作的。但如果你想调查,JVM源代码可以下载…)

“鲁莽”意思是“我不知道它为什么会占用内存”?除非它的增长,以填补最大的空间,我不会称之为“泄漏”本身;我倾向于(a)将其归因于JVM所做的事情,或者(b)使用分析工具深入挖掘。你是如何运行该程序的?@immibis我在eclipse中运行它,但即使我尝试将其作为导出的jar文件运行,它仍然存在过度消耗问题。进行堆转储并运行eclipse MAT“我没有更改代码中的任何内容,它只是停止了操作。”--嗯……它可能只是垃圾收集:-)即使我删除
System.out.println(新字符串(散列));
代码,应用程序仍然消耗相同的内存量。(任务管理器报告)@NicholasHollander好的,那就不是问题了,谢谢你的检查。
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
    }
}