线程会降低PC的速度并导致java.lang.OutOfMemoryError

时间:2013-08-18 18:06:42

标签: java multithreading

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

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

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(); }

    }

}

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

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

如何解决问题,如何让线程使用更少的内存,以免降低PC速度。

以下是main方法中的调用。

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

4 个答案:

答案 0 :(得分:5)

从它的外观来看,你正在为每个屏幕截图创建一个单独的线程,这将使你快速运行内存。相反,你应该有一个单独的线程,它在循环中,睡眠并不时截取屏幕截图。

    public class ScreenshotTaker implements Runnable {



        private volatile boolean done = false;



        public void run( ) {

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

            ...sleep ...
            }

        }

        public void setDone( ) {

            done = true;

        }

    }

答案 1 :(得分:3)

你要求麻烦,你应该去实施一些限制你的线程数的Threadpool实现。要了解使用情况,请参阅官方教程:http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html

与解决方案一样:

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

您创建线程的速度超过了处理工作的速度。基本上你只是说尽可能快地创建多个线程,在创建新线程之前无法保证它们的处理数。所以这只是程序死亡的时间问题(资源耗尽= CPU +内存)

答案 2 :(得分:1)

你应该在这里限制线程创建过程

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

这些线程几乎一起开始,让你的记忆充满活力。

答案 3 :(得分:0)

如此代码很少,很难说,但你绝对应该做到以下几点:

Robot r;
BufferedImage img;

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