2014-11-05 27 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