2014-11-05 3 views
1

сегодня я немного исказился с открытием/масштабированием/отображением изображения на Java и написал немного кода, чтобы открыть файл изображения, масштабировать его случайным образом и отображать его на короткое время.Утечка памяти (?) При отображении изображений в java

Проблема: после отображения ее как 100-1000 раз, используемая память моего «javaw.exe» растет и растет, она даже достигла 1 ГБ памяти.

Я не знаю, где утечка памяти в моем коде, так как единственная память, в которой есть вещи, - это мои picures, и есть только 2 (исходное изображение и тот, который получает масштабирование, которое всегда присваивается одной и той же переменной (temp), поэтому «старшие» должны быть сняты 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); 


} 

Это мой первый пост, поэтому, пожалуйста, задавайте вопросы, если я неясен

заранее!

EDIT: Я, мониторинг которых javaw.exe памяти нуждаясь

1 фотография отображается: 75M 100 фотографий отображаются: 330M 1000 фотографий отображаются: 2,4G

EDIT 2:

I теперь применили ваш полезный совет, но у меня все еще есть растущее количество памяти, и мой графический объект больше отображается. 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? В конце концов, у него не хватает памяти или сбор мусора в конечном итоге? –

+0

Вы создаете новые кадры в цикле, но никогда не закрываете их (вы просто делаете их невидимыми), и каждый из них имеет измененное изображение. Вы должны получать утечки памяти. Сбор мусора никогда не может произойти, пока эти рамки вокруг. Кроме того, вы находитесь в главной теме. Это никогда не сработает, у вас в конечном итоге закончится нехватка памяти и сбой виртуальной машины. – mttdbrd

+0

Возможно, вам придется изменить конфигурационный файл vm и предоставить ему больше памяти. – ha9u63ar

ответ

1

Код ниже должен делать то, что вы хотите. Я использовал Timer вместо Thread.sleep. Вы связываете EDT. Я также просто рисую изображение в контейнере. Вероятно, вы должны использовать 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

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

+0

Хорошо спасибо за полезный совет! – LBecker

+0

Вы правы. Надеюсь, теперь это немного более полно. –

Смежные вопросы