简体   繁体   English

在Java中显示图像时出现内存泄漏(?)

[英]Memory Leak(?) when displaying images in java

today I kinda fiddled around with image opening/scaling/displaying in Java and wrote a bit of code to open an Image File, scale it randomly and display it for a short time. 今天,我有点用Java来打开/缩放/显示图像,并写了一些代码来打开一个图像文件,随机缩放它并显示一小段时间。

The problem is: After displaying it for like 100-1000 times, the used memory of my "javaw.exe" grows and grows, it even reached 1 GB of memory space. 问题是:在显示了100-1000次之后,我的“ javaw.exe”的已用内存越来越大,甚至达到1 GB的内存空间。

I dont know where the memory leak in my code is since the only memory eating things are my picures and there are only 2 (the original image and the one who is getting scaled, which is always assigned to the same variable(temp) so the "older" ones should be picked off by the GC), maybe you guys could have a look over it, its pretty simple. 我不知道代码中的内存泄漏在哪里,因为唯一的内存吃东西是我的照片,只有2张(原始图像和正在缩放的​​图像,总是分配给相同的变量(温度),因此“较旧的”应该由GC挑选),也许你们可以看看它,它非常简单。

1) You choose an image from your hard drive 1)您从硬盘上选择一个图像

2) It gets scaled randomly 2)随机缩放

3) Its displayed for a short amount of time and then disappears 3)短时间显示然后消失

4) go to 2) 4)转到2)

To scale the image I used this library: http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/ 要缩放图像,我使用了该库: http : //www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;

import org.imgscalr.Scalr;

public static void main(String[] args) throws IOException, InterruptedException {


    JFileChooser chooser = new JFileChooser();
    chooser.showOpenDialog(null);

    BufferedImage originalImage = ImageIO.read(chooser.getSelectedFile());
    BufferedImage temp;


    while(true){

        int width = (int) ((Math.random()*1000)+1); 
        int height = (int) ((Math.random()*1000)+1);

        Thread.sleep(1000);

        temp = Scalr.resize(originalImage,Scalr.Mode.FIT_EXACT, width, height);


        showImage(temp, 800);

    }

}

static void showImage(BufferedImage v,long length) throws InterruptedException {


    JFrame frame = new JFrame();
    frame.add(new JLabel(new ImageIcon(v)));
    frame.setSize(v.getWidth(), v.getHeight());

    frame.setVisible(true);
    Thread.sleep(length);
    frame.setVisible(false);


}

This is my first time posting here, so please ask questions if I am unclear 这是我第一次在这里发布信息,如果不清楚,请提出问题

thanks in advance! 提前致谢!

EDIT: I monitored the memory javaw.exe is needing 编辑:我监视内存javaw.exe需要

1 picture displayed: 75M 100 pictures displayed: 330M 1000 pictures displayed: 2,4G 显示1张照片:75M显示100张照片:330M显示1000张照片:2,4G

EDIT 2: 编辑2:

I now have applied your helpful advice but I still have a growing amount of memory and my Images arent displayed anymore.. The JFrames are empty. 现在,我已经应用了您的有用建议,但是我的内存仍在增长,并且我的图像也不再显示。.JFrames是空的。

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

import org.imgscalr.Scalr;

public class App {

    public static void main(String[] args) throws IOException, InterruptedException {


        JFileChooser chooser = new JFileChooser();
        chooser.showOpenDialog(null);

        BufferedImage originalImage = ImageIO.read(chooser.getSelectedFile());
        BufferedImage temp;

        JFrame frame = new JFrame();


        while(true){

            int width = (int) ((Math.random()*1000)+1); 
            int height = (int) ((Math.random()*1000)+1);

            Thread.sleep(1000);

            temp = Scalr.resize(originalImage,Scalr.Mode.FIT_EXACT, width, height);


            showImage(temp, 500, frame);

        }

    }

    static void showImage(BufferedImage v,long length, JFrame frame) throws InterruptedException {

        SwingUtilities.invokeLater(
                () -> {


                    frame.removeAll();
                    frame.revalidate();
                    frame.repaint();

                    frame.add(new JLabel(new ImageIcon(v)));
                    frame.setSize(v.getWidth(), v.getHeight());

                    frame.setVisible(true);
                    try {
                        Thread.sleep(length);
                    } catch (Exception e) {}
                    frame.setVisible(false);

                    frame.dispose();
                });



    }

}

Maybe I put your advice in the wrong places in my code. 也许我把您的建议放在代码的错误位置。

You might want to try 您可能要尝试

originalImage.flush();
originalImage = null;
temp.flush();
temp = null;

but there is no guarantee when your image will get garbage collected 但是无法保证您的图片何时会被垃圾收集

Apart from that you should also consider clearing and reusing the same JFrame. 除此之外,您还应该考虑清除并重新使用相同的JFrame。

removeAll();//or remove the previous JLabel
revalidate();
repaint();

Also the proper way to display a JFrame is by using the SwingUtilities invokeLater method to make sure this "job" is placed on the Event Dispatch Thread (EDT). 同样,显示JFrame的正确方法是使用SwingUtilities invokeLater方法,以确保将此“作业”放置在事件调度线程(EDT)上。

 // schedule this for the event dispatch thread (edt)
 SwingUtilities.invokeLater(yourJFrame);

The code below should do what you want. 下面的代码应做您想要的。 I used a Timer instead of Thread.sleep. 我使用计时器而不是Thread.sleep。 You're tying up the EDT. 您正在捆绑EDT。 I also just draw the image in the container. 我也只是在容器中绘制图像。 You should probably use a JPanel instead (add it to the JFrame and override its paintComponent method). 您可能应该改用JPanel(将其添加到JFrame并覆盖其paintComponent方法)。 I also cleaned up the methods a little. 我还清理了一些方法。

import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import org.imgscalr.Scalr;

public class App extends JFrame implements ActionListener{

        BufferedImage originalImage = null;
        BufferedImage temp = null;
        JFileChooser chooser = null;

        public App(){

                setVisible(true);
        }

        public static void main(String[] args) throws IOException, InterruptedException {


                SwingUtilities.invokeLater(
                                () -> {
                                        App app = new App();

                                        Timer timer = new Timer(1000, app);
                                        timer.start();

                                });

        }

        @Override
        public void actionPerformed(ActionEvent ae){
                if(null == chooser){
                        chooser = new JFileChooser();
                        chooser.showOpenDialog(this);
                        loadImage();
                }
                showImage();
                repaint();
        }

        @Override
        public void paint(Graphics g){
                super.paint(g);
                if(null == temp){
                        return;
                }
                g.drawImage(temp, 0, 0, null);
        }

        public void loadImage(){

                try{
                        originalImage = ImageIO.read(chooser.getSelectedFile());
                } catch(IOException ioe){
                        ioe.printStackTrace();
                }
        }

        public void showImage() {
                int width = (int) ((Math.random()*1000)+1); 
                int height = (int) ((Math.random()*1000)+1);
                temp = Scalr.resize(originalImage,Scalr.Mode.BEST_FIT_BOTH, width, height);
                setSize(width, height);
        }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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