2014-11-05 26 views
1

今天我有点用Java打开/缩放/显示图像,并编写了一些代码来打开图像文件,随机缩放并显示一小段时间。在java中显示图像时的内存泄漏(?)

问题是:显示它像100-1000次后,我的“javaw.exe”使用的内存增长和增长,它甚至达到1 GB的内存空间。

我不知道我的代码中的内存泄漏的地方是因为唯一的内存吃东西是我的picures,只有2(原始图像和得到缩放的人,它总是分配给相同的变量温度),所以老年人应该被GC挑选出来),也许你们可以看看它,它非常简单。

1)您可以选择从硬盘

2)被随机缩放

3)及其在很短的时间量所显示的图像,然后消失

4)到2 )

要缩放我用这个库中的图片: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); 


} 

这是我第一次在这里发帖,所以如果我不清楚请提问

在此先感谢!

编辑:我监视的存储器javaw.exe的正需要

显示1张图片:75M显示 100张图片显示330M 1000图片:2,4G

编辑2:

我现在已经应用了您的有用建议,但我仍然有越来越多的内存,并且我的图像不再显示。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(); 
       }); 



    } 

} 

也许我把你的建议放在我的代码错误的地方。

+2

您给Java多少内存?它最终会耗尽内存,还是最终会收集垃圾回收? – 2014-11-05 15:00:28

+0

您正在循环中创建新框架,但从不关闭它们(只是使它们不可见),并且每个框架都有一个调整大小的图像。你应该得到内存泄漏。垃圾收集永远不会发生,只要这些帧在附近。另外,你在主线程中。这永远不会起作用,你最终将耗尽内存并使虚拟机崩溃。 – mttdbrd 2014-11-05 15:00:42

+0

您可能必须修改vm配置文件并为其提供更多内存。 – ha9u63ar 2014-11-05 15:03:39

回答

1

下面的代码应该做你想做的。我使用了Timer而不是Thread.sleep。你正在捆绑美国东部时间。我也只是在容器中绘制图像。你应该使用JPanel来代替(将它添加到JFrame并覆盖它的paintComponent方法)。我也清理了一些方法。

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); 
     } 
} 
+0

是的,那正是我想要做的。非常感谢! – LBecker 2014-11-06 11:53:06

1

你可能想尝试

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

但如果你的形象会得到垃圾回收

除此之外,你也应该考虑清除和重复使用相同的JFrame难保。

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

还显示一个JFrame的正确方法是使用SwingUtilities类的invokeLater方法来确保这个“工作”被放置在事件指派线程(EDT)。

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

这不起作用,因为他保留了JFrames。那些需要清理。并且它在主应用程序线程上。这也需要修复。如果你能解决所有的问题,我会乐观的。 – mttdbrd 2014-11-05 15:03:07

+0

好的谢谢你的建议! – LBecker 2014-11-05 15:20:42

+0

你说得对。希望现在有点更完整。 – 2014-11-05 15:21:30