java - 使用 ImageIO.write 时出现 OutOfMemory

标签 java out-of-memory javax.imageio

即使 BlockingQueue 为空,我的 saveScreenShot 线程上也会出现 OutOfMemory 错误

在我的 Main 中有以下变量存储图像

public static BlockingQueue<ImageSaveData> imageQueue1 = new LinkedBlockingQueue<ImageSaveData>();
    public static BlockingQueue<ImageSaveData> imageQueue2 = new LinkedBlockingQueue<ImageSaveData>();
    public static BlockingQueue<ImageSaveData> imageQueue3 = new LinkedBlockingQueue<ImageSaveData>();
    public static BlockingQueue<ImageSaveData> imageQueue4 = new LinkedBlockingQueue<ImageSaveData>();

这是我的 ImageSaveData 类

import java.awt.image.BufferedImage;

public class ImageSaveData
{
    private String fileNumber;
    private BufferedImage image;

    public ImageSaveData(String fileNumber, BufferedImage image)
    {
        this.fileNumber = fileNumber;
        this.image = image;
    }

    public String getFileNumber()
    {
        return fileNumber;
    }

    public BufferedImage getImage()
    {
        return image;
    }
}

这是我的线程,它截取屏幕截图并将其保存到 imageQueueX

    // long start = System.currentTimeMillis();
    synchronized (runner)
    {
        int imageCount = 0;
        int maxCount = 0;
        boolean hasMessage = false;
        String[] countFormat =
        {
                "00000000", "0000000", "000000", "00000", "0000", "000", "00", "0"
        };
        // 10
        while (true)
        {
            if (maxCount++ < 1000000010)
            {
                try
                {
                    BufferedImage image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
                    String imageOutNumb = "";
                    if (imageCount < 10) imageOutNumb = countFormat[0] + imageCount++;
                    else if (imageCount < 100) imageOutNumb = countFormat[1] + imageCount++;
                    else if (imageCount < 1000) imageOutNumb = countFormat[2] + imageCount++;
                    else if (imageCount < 10000) imageOutNumb = countFormat[3] + imageCount++;
                    else if (imageCount < 100000) imageOutNumb = countFormat[4] + imageCount++;
                    else if (imageCount < 1000000) imageOutNumb = countFormat[5] + imageCount++;
                    else if (imageCount < 10000000) imageOutNumb = countFormat[6] + imageCount++;
                    else if (imageCount < 100000000) imageOutNumb = countFormat[7] + imageCount++;
                    else imageOutNumb = "" + imageCount++;

                    ImageSaveData imageSaveData = new ImageSaveData(imageOutNumb, image);

                    while (true)
                    {
                        if (Main.imageQueue1.offer(imageSaveData, 1, TimeUnit.NANOSECONDS)) break;
                        if (Main.imageQueue2.offer(imageSaveData, 1, TimeUnit.NANOSECONDS)) break;
                        if (Main.imageQueue3.offer(imageSaveData, 1, TimeUnit.NANOSECONDS)) break;
                        if (Main.imageQueue4.offer(imageSaveData, 1, TimeUnit.NANOSECONDS)) break;
                    }
                }
                catch (HeadlessException | AWTException e)
                {
                    e.printStackTrace();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                catch(OutOfMemoryError e)
                {
                    try
                    {
                        runner.sleep(1);
                    }
                    catch (InterruptedException e1)
                    {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
                try
                {
                    runner.sleep(34);
                }
                catch (InterruptedException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            else
            {
                if (hasMessage)
                {
                    try
                    {
                        System.out.println(Main.imageQueue1.isEmpty());
                        System.out.println(Main.imageQueue2.isEmpty());
                        System.out.println(Main.imageQueue3.isEmpty());
                        System.out.println(Main.imageQueue4.isEmpty());
                    }
                    catch (Exception e)
                    {

                    }
                }
                else
                {
                    System.out.println("We Have Finished saving images to memory");
                    hasMessage = true;
                }
            }
        }
    }

我有 3 个消费者线程,唯一的区别是文件路径不同

    // long start = System.currentTimeMillis();
    synchronized (runner)
    {
        String PathName = "\\\\DELL\\Maxtor\\aJordan\\";
        while (true)
        {
            try
            {
                ImageSaveData imageData1 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);
                ImageSaveData imageData2 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);
                ImageSaveData imageData3 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);
                ImageSaveData imageData4 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);
                if (imageData1 != null) ImageIO.write(imageData1.getImage(), "png", new File(PathName + imageData1.getFileNumber() + ".png"));
                if (imageData2 != null) ImageIO.write(imageData2.getImage(), "png", new File(PathName + imageData2.getFileNumber() + ".png"));
                if (imageData3 != null) ImageIO.write(imageData3.getImage(), "png", new File(PathName + imageData3.getFileNumber() + ".png"));
                if (imageData4 != null) ImageIO.write(imageData4.getImage(), "png", new File(PathName + imageData4.getFileNumber() + ".png"));


            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

错误

java.lang.OutOfMemoryError: Java heap space
    at sun.awt.windows.WRobotPeer.getRGBPixels(Unknown Source)
    at java.awt.Robot.createScreenCapture(Unknown Source)
    at TakeShothandler1.run(TakeShothandler1.java:48)
    at java.lang.Thread.run(Unknown Source)

第 48 行是

BufferedImage image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));

最佳答案

您的队列容量是多少?当前堆大小是多少?

每个屏幕截图的大小约为 3-10 MB,具体取决于您的分辨率(例如 1024x768x32 分辨率:1024x768x4bytes/pixel=3.14MB),并且您获取它们的速度可能比将它们写入磁盘的速度更快。

根据您的堆大小和队列容量,清理可用堆可能根本不需要很长时间。

另外,我不确定(您可能在其他地方有其他代码),但看起来您可能只从消费者线程中的一个队列进行轮询:

ImageSaveData imageData1 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);
ImageSaveData imageData2 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);
ImageSaveData imageData3 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);
ImageSaveData imageData4 = Main.imageQueue1.poll(1, TimeUnit.NANOSECONDS);

编辑:哇,没有意识到这个帖子已经有两年了。

关于java - 使用 ImageIO.write 时出现 OutOfMemory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15858880/

相关文章:

java无限循环调用datainputstream收到内存不足异常

java - 解码 Google App Engine 上作为电子邮件收到的 Base64 图像

Java 位图 RLE8 格式

javax.imageio - Java 9 ImageIO read\write 给出了与 Java 8 不同的结果

java - 使用 spark 将 POST 正文解析为 java 对象

java - Android数据库文件结构是什么

java - WAR 无法在 AWS 中的 jetty9 上启动,但可以在本地安装上运行

C++ 内存不足异常测试

java - 等待 Java 进程的答复?

mysql - 如何修复错误代码: 1041 on heroku MySql free plan?