【问题标题】:Outofmemory exception loading image files in Java在 Java 中加载图像文件的内存不足异常
【发布时间】:2016-02-10 16:48:56
【问题描述】:

我在加载图像文件时遇到问题。 有2个案例,我测试过。问题只出现在第一个。在这两种情况下,都会出现一个 JDialog 窗口,显示一个 缩小的图像。 300ms 后该窗口自动关闭(ImageDialog 和 CardPrinter 的构造函数中有一个计时器;这仅用于调试)。 在生产版本中,程序必须能够在 JDialog 中加载 30-40 个图像(一张一张)。用户键入一些文本,然后单击按钮以显示下一个图像。 要加载图像,我在这两种情况下都使用 ImageIO.read()。或者我使用 CMYKJPEGImage (http://www.randelshofer.ch/blog/2011/08/reading-cmyk-jpeg-images-with-java-imageio/) 但它也会产生异常。 在 Main 中,myTimer 会不断打开带有图像文件的 JDialog(应通过设置变量 pathtofiles 使用绝对路径调用 listFilesRecurse())。

案例 1) 使用覆盖布局管理器(Main.java、CardPrinter.java、IDCardLayout.java)在 JDialog 中加载图像。 为此,来自 'CardPrinter cp=null;' 的行到 'cp.dispose();'在 Main.java 中必须取消注释。棘手的部分在 addIDCard()@CardPrinter 中。 这将是建立的布局。在此paintComponent()@IDCardLayout 将被调用之后,如果对话窗口的内容应该被实现。 看起来,加载的图片不会被破坏,而且内存已经满了(在Window的任务管理器中可以看到内存使用情况)。

案例 2) 在没有布局管理器的 JDialog 中加载图像(Main.java、ImageDialog.java)。 (取消注释 'mn.showDialog(mn.frame, file);' 行)。 完美运行。没有例外!

函数 ImageIO.read() 应该没问题,因为在 2. 的情况下,没有错误(即使代码运行了 20 分钟)。 奇怪的是,布局管理器似乎在第一种情况下会阻止 GC 卸载未使用的图像...
1.case中的问题应该在CTR@CardPrinter和addIDCard()@CardPrinter。在 CTR 中,我使用 OverlayLayout。在 2.case 中,根本没有 Layoutmanager。
Java 版本为:Windows7 SP1 上的 1.7.0_80。
有人可以帮帮我吗?

提前谢谢你, 丹尼尔

例外:

线程“AWT-EventQueue-0”java.lang.OutOfMemoryError 中的异常:Java 堆空间 在 java.awt.image.DataBufferByte.(DataBufferByte.java:92) 在 java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:415) 在 java.awt.image.Raster.createWritableRaster(Raster.java:941) 在 javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1073) 在 javax.imageio.ImageReader.getDestination(ImageReader.java:2896) 在 com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1066) 在 com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1034) 在 javax.imageio.ImageIO.read(ImageIO.java:1448) 在 javax.imageio.ImageIO.read(ImageIO.java:1308) 在 test.IDCardLayout.loadPicture(IDCardLayout.java:128) 在 test.CardPrinter.addIDCard(CardPrinter.java:142) 在 test.CardPrinter.(CardPrinter.java:62) 在 test.CardPrinter.createDialog(CardPrinter.java:91) 在 test.Main$1.actionPerformed(Main.java:69) 在 javax.swing.Timer.fireActionPerformed(Timer.java:312) 在 javax.swing.Timer$DoPostEvent.run(Timer.java:244) 在 java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312) 在 java.awt.EventQueue.dispatchEventImpl(EventQueue.java:745) 在 java.awt.EventQueue.access$300(EventQueue.java:103) 在 java.awt.EventQueue$3.run(EventQueue.java:706) 在 java.awt.EventQueue$3.run(EventQueue.java:704) 在 java.security.AccessController.doPrivileged(本机方法) 在 java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 在 java.awt.EventQueue.dispatchEvent(EventQueue.java:715) 在 java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) 在 java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) 在 java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) 在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) 在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) 在 java.awt.EventDispatchThread.run(EventDispatchThread.java:91)


package test;
/*Main.java*/


import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Main {
    JFrame frame;


    //list files recursively, using a filter (pattern). If pattern=*, all files will be listed.
    public static void listFilesRecurse(String fullpath, String pattern[], Vector<File> foundFiles) throws IOException {
        File dir = new File(fullpath);
        File list[] = dir.listFiles();
        for(File f: list) {
            if( !f.isDirectory() ) {
                for(String pt: pattern) {
                    if(pt.equals("*")) {
                        foundFiles.add(f);
                        break;
                    }
                    else if( f.getAbsolutePath().toUpperCase().endsWith(pt.toUpperCase()) ) {
                        foundFiles.add(f);
                        break;
                    }
                }
            } else {
                listFilesRecurse(f.getAbsolutePath(), pattern, foundFiles);
            }
        }
    }


public static void main(String[] args) {
    final Main mn = new Main();
    final String pathtofiles = "\\path\\to\\files\\";

    ActionListener task = new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            Vector<File> list = new Vector<File>();
            System.out.println("\nListing files ...");
            try {
                listFilesRecurse(pathtofiles, new String[]{"jpg", "png", "jpeg"}, list);
            } catch (IOException e) {
                e.printStackTrace();
            }
            for(int index=0; index<list.size(); index++) {
                String file = list.get(index).getAbsolutePath();
                System.out.println("\nLoading image - " + index + ": " + file);

                //mn.showDialog(mn.frame, file);


                CardPrinter cp=null;
                try {
                    cp = CardPrinter.createDialog(mn.frame, "Max",
                                                  "Muster", "1122", "12345678", "01/2018", file);
                } catch (Exception e) {
                    e.printStackTrace();
                    continue; //break;  //return;
                }
                cp.setVisible(true);
                cp.dispose();
            }
        }
    };
    final Timer myTimer = new Timer(100,  task);
    myTimer.setRepeats(true);


    JFrame frame = new JFrame("JFrame Example");
    mn.frame = frame;

    JPanel panel = new JPanel(); 
    panel.setLayout(new FlowLayout());

    JLabel label = new JLabel("This is a label!"); 
    JButton button = new JButton(); 

    button.setText("Press me");
    button.addActionListener( new ActionListener() {
        public void actionPerformed(ActionEvent actionEvent) {
            myTimer.start();
        }
    });

    panel.add(label);
    panel.add(button);
    frame.add(panel);
    frame.setSize(300, 300);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}


//opens the dialog that display an image (file).
public void showDialog(JFrame fr, String file) {
    ImageDialog imgd = new ImageDialog(fr, "Testdialog", file);
    imgd.setSize(300, 300);
    imgd.setModal(true);
    imgd.setLocation(250, 250);
    imgd.setVisible(true);
}

}

package test;
/*ImageDialog.java*/

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

import javax.imageio.ImageIO;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.Timer;

import org.monte.cmykdemo.CMYKJPEGImage;


public class ImageDialog extends JDialog {
    String file;


    public ImageDialog(JFrame frame, String title, String file) {
        super(frame, title);
        this.file = file;

        //######For debugging only. This will close the dialog window after 300 ms (by calling ImageDialog.this.setVisible(false);).
        ActionListener task = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                ImageDialog.this.dispose();
            }
        };
        Timer cl = new Timer(300, task);
        cl.start();
        //#######
    }


    //renders the picture on screen.
    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        setRenderingHints(g2d);

        BufferedImage img=null;
        try {
            img = loadPicture(this.file);
        } catch (IOException e) {
            e.printStackTrace();
        }

        g2d.setColor(Color.BLUE);
        g2d.drawRect(0, 0, this.getWidth(), this.getHeight());
        g2d.drawImage(img, 10, 10,  80,  80,  null, null);
    }


    void setRenderingHints(Graphics2D g2) {
        g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
        g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
        g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
    }

    public static BufferedImage loadPicture(String fullpath) throws IOException {
        System.out.println("\nloadPicture(): " + fullpath);
        //BufferedImage img = (BufferedImage) CMYKJPEGImage.loadImage( fullpath );
        BufferedImage img = (BufferedImage) ImageIO.read( new File(fullpath) );
        return img;
    }
}

package test;
/*CardPrinter.java*/

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PageFormat;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.BorderFactory;
import javax.swing.JButton;


public class CardPrinter extends JDialog /*implements Printable*/ {
  protected JPanel jp;
  protected JTextField tx;
  protected JLabel lblCounter;
  protected IDCardLayout idcard;
  protected String vorname, nachname, id, gueltig, bild;

  protected String chipid;


  protected CardPrinter(Window owner, String vorname, String nachname, String id, String chipid,
                        String gueltig, String bild /*, DataReceiver drv*/) throws IOException {
      super((Window)owner, "Assign_ChipID_DialogObject");
      this.bild = bild;
      //this.datareceiver = drv;
      setTitle("Assign ID");
      setModalityType(JDialog.DEFAULT_MODALITY_TYPE);
      setResizable(false);

      jp = new JPanel();
      jp.setLayout(null);
      jp.setOpaque(false);

      addIDCard();
      //setupButtons();

      //setSize(this.getPreferredSize().width, this.getPreferredSize().height);
      setSize(250, 250); //+++
      setLocation(300, 300); //+++

      //Overlay components: tx overlaps idcard
      JPanel cnt = new JPanel();
      cnt.setLayout(new OverlayLayout(cnt));
      cnt.add(jp);
      getContentPane().add(cnt);

      setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);


      //######For debugging only. This will close the dialog window after 300 ms (by calling CardPrinter.this.setVisible(false);).
      ActionListener task = new ActionListener() {
          public void actionPerformed(ActionEvent evt) {
              CardPrinter.this.setVisible(false);
          }
      };
      Timer closeWnd = new Timer(300, task);
      closeWnd.start();
      //######
  }


  //use this to create an instance of this class.
  public static CardPrinter createDialog(Window owner, String vorname,
                String nachname, String id, String chipid, String gueltig, String bild  /*, DataReceiver drv*/) throws IOException {
      return new CardPrinter(owner, vorname, nachname, id, chipid, gueltig, bild  /*, drv*/);
  }


  protected void addIDCard() throws IOException {
      int idcard_move_vert=15, idcard_move_hor=76;
      tx = new JTextField(this.chipid, 8);
      jp.add(tx);
      tx.setBounds(idcard_move_hor+130, idcard_move_vert+6, 70, 20);
      Border border = BorderFactory.createLineBorder(Color.RED);
      tx.setBorder(border);
      tx.requestFocus();

      lblCounter = new JLabel("");
      lblCounter.setBounds(idcard_move_hor+270, idcard_move_vert-6, 40, 30);
      jp.add(lblCounter);
      lblCounter.requestFocus();

      System.out.println("\naddIDCard() ...");

      BufferedImage picture = IDCardLayout.loadPicture(this.bild);
      idcard = new IDCardLayout(/*this.vorname, this.nachname, this.id,*/ picture, this.bild  /*, this.gueltig*/);

      idcard.setLayout(null);
      //idcard.setBounds(idcard_move_hor, idcard_move_vert, idcard.getPreferredSize().width, idcard.getPreferredSize().height);
      idcard.setBounds(idcard_move_hor, idcard_move_vert, 50, 60);
      idcard.setBorder( new LineBorder(Color.BLACK) );
      jp.add(idcard);

      //repaint();
  }
}

package test;
/*IDCardLayout.java*/

import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import org.monte.cmykdemo.CMYKJPEGImage;


public class IDCardLayout extends JPanel {
    private BufferedImage bild;
    private String bildfile;


    public IDCardLayout(BufferedImage photo, String bildfile) {
        this.bild = photo;
        this.bildfile = bildfile;
    }


    /**
     * Render graphics to the screen.
     */
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        System.out.println("\npaintComponent() ...");
        prepareGraphics(g2d);
    }


    public static BufferedImage loadPicture(String fullpath) throws IOException {
        //BufferedImage img = (BufferedImage) CMYKJPEGImage.loadImage( f.getAbsolutePath() );
        BufferedImage img = (BufferedImage) ImageIO.read( new File(fullpath) );

        return img;
    }


    //changing the rendering hints has no effect on Outofmemory-exception.
    protected void setRenderingHints(Graphics2D g2, boolean normalText) {
        if(true) {
            g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
            g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
            g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
        }
    }


    /**
     * Renders graphics to the screen.
     */
    protected void prepareGraphics(Graphics2D g2) {
        setRenderingHints(g2, true);

        double newHeight = 60;
        double scwidth = ( ((double)newHeight / (double)this.bild.getHeight()) ) * (double)this.bild.getWidth();
        System.out.println("\nprepareGraphics() ..." + this.bildfile);
        g2.drawImage(this.bild,  5,  5,
                    (int)scwidth,
                    (int)newHeight,
                    null, null);
    }
}

【问题讨论】:

  • 代码很多,这肯定会有所帮助 - stackoverflow.com/help/mcve
  • 您正在创建大量图像 - 您希望发生什么?我们不会追踪你的程序
  • 虽然类似的问题可能是这里的主题,但这个问题的解决方式不太可能帮助未来的读者。

标签: java image exception loading


【解决方案1】:

问题解决了。我不再使用 OverlayLayout 类了。布局看起来很不一样,但现在可以了。

【讨论】:

    猜你喜欢
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    相关资源
    最近更新 更多