0

我正在做的是制作一个程序,该程序不断截取用户桌面的屏幕截图,并根据用户的需要保存它们。最初,我调用了在一段时间内捕获的方法,但这太慢了,我需要尽快拍摄尽可能多的图像。我决定做的是使用线程。

当程序运行时,我的电脑变得很慢(即鼠标闪烁、移动缓慢等),当我停止程序时,我收到以下错误。

Exception in thread "Thread-294" java.lang.OutOfMemoryError: Java heap space
at sun.awt.windows.WRobotPeer.getRGBPixels(Unknown Source)
at java.awt.Robot.createScreenCapture(Unknown Source)
at maple.Record.run(Record.java:29)

这是产生错误的行。

img = r.createScreenCapture(new Rectangle (0, 0, width, height));

这是我的包含线程的类。

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.media.MediaLocator;

public class Record implements Runnable {

    Robot r;
    static int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
    static int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
    BufferedImage img;
    public static boolean stop = false;

    public void run() {

        try {

            r = new Robot();
            img = r.createScreenCapture(new Rectangle (0, 0, width, height));
            ImageIO.write(img, "png", new File(JavCapture.tmpLocation + "\\tmp\\" + System.currentTimeMillis() + ".png"));

        } catch (IOException | AWTException e) { e.printStackTrace(); }

    }

}

当我调用已编辑为使用 .png 文件的 JpegImagesToMovies 时会产生错误。

请查看链接以获取更多信息。

我该如何解决这个问题,以及如何让线程使用更少的内存,这样它就不会减慢 PC 的速度。

这是main方法中的调用。

do {    
    (new Thread(new Record())).start();
} while (!Record.stop);
4

4 回答 4

5

从外观上看,您正在为每个屏幕截图创建一个单独的线程,这将很快耗尽您的内存。相反,您应该有一个单独的线程,该线程处于循环中,不时休眠并截取屏幕截图。

    public class ScreenshotTaker implements Runnable {



        private volatile boolean done = false;



        public void run( ) {

            while (!done) {
            ... take screenshot...

            ...sleep ...
            }

        }

        public void setDone( ) {

            done = true;

        }

    }
于 2013-08-18T18:13:01.900 回答
3

你是在自找麻烦,你应该寻求一些Threadpool会限制你的线程数的实现。要了解用法,请参阅官方教程:http ://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html

与您的解决方案一样:

do {    
    (new Thread(new Record())).start();
} while (!Record.stop);

您创建线程的速度比他们处理工作的速度要快。基本上你只是说尽可能快地创建许多线程,不能保证在创建新线程之前处理它们的数量。所以程序死掉只是时间问题(资源耗尽 = CPU + 内存)

于 2013-08-18T18:18:48.250 回答
1

您应该在此处限制线程创建过程

(new Thread(new Record())).start(); 

这些线程几乎一起开始并且使您的记忆膨胀。

于 2013-08-18T18:20:32.303 回答
0

有这么少的代码很难说,但你一定要做到以下几点:

Robot r;
BufferedImage img;

进入局部变量而不是实例变量。您拥有它的方式,它们引用的对象将比您的程序实际需要它们的时间长得多。这是通往OutOfMemoryException.

于 2013-08-18T18:11:16.510 回答