Управление использованием памяти при получении большого количества скриншотов в Java

Я разрабатываю программное обеспечение на Java, которое постоянно делает снимки экрана рабочего стола, сохраняет их в объекте BufferedImage, а затем записывает в файлы jpg. В какой-то момент программа вызывает java.lang.OutOfMemoryError: Исключение пространства кучи Java. Поскольку я делаю снимок экрана и сохраняю его как файл, мне больше не нужны предыдущие объекты BufferedImage в памяти, поэтому я могу их выбросить. Java, похоже, не распознает эти объекты, поэтому они, вероятно, все еще находятся в памяти. Есть ли способ удалить их из памяти JVM, чтобы она не закончилась? Непрерывный вызов System.gc(), вероятно, не поможет. Любые идеи?

Вот код для справки:

public BufferedImage getScreenShot() {

    BufferedImage screenImage = null;
    try {

        GraphicsEnvironment ge= GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice[] screens=ge.getScreenDevices();
        Rectangle allScreenBounds=new Rectangle();
        for(GraphicsDevice screen: screens)
        {
            Rectangle screenbounds = screen.getDefaultConfiguration().getBounds();
            allScreenBounds.width+=screenbounds.width;
            allScreenBounds.height=Math.max(allScreenBounds.height, screenbounds.height);
        }


        Robot robot = new Robot();
        screenImage = robot.createScreenCapture(allScreenBounds);
    } catch (Exception ex) {
        Logger.getLogger(Screen.class.getName()).log(Level.SEVERE, null, ex);
    }
    return screenImage;
}

Затем у меня просто есть цикл, который постоянно вызывает метод для создания объекта BufferedImage, изменяет его размер и записывает в такой файл:

while(true){
  FileImageOutputStream out = new FileImageOutputStream(f);
  writer.setOutput(out);
  IIOImage image = new IIOImage(ImageUtils.resize(getScreenShot(), width, height),null, null);
  writer.write(null, image, iwp);
  writer.dispose();
}

person Paul    schedule 27.01.2012    source источник
comment
вы можете стать профессионалом и использовать встроенную функцию Java. Я еще не использовал его, но он позволяет вам использовать c/c++ в вашем java-коде, что обеспечивает более высокую производительность.   -  person L7ColWinters    schedule 27.01.2012
comment
System.gc() не гарантирует сбор мусора во время вызова, поэтому этот вариант не гарантируется. Опубликуйте свой код, который может помочь в выявлении любых утечек памяти.   -  person kosa    schedule 27.01.2012
comment
Вы вызывали flush() для буферизованного изображения?   -  person Scorpion    schedule 27.01.2012
comment
@ Скорпион нет, не видел. Как флеш помогает освободить память?   -  person Paul    schedule 27.01.2012


Ответы (2)


arrow_upward
5
arrow_downward

Вам просто нужно удалить ссылочные переменные ранее использовавшихся объектов BufferedImage. Тогда сборщик мусора будет автоматически освобождать занимаемую ими память, когда это необходимо.

Поскольку вы постоянно делаете снимки экрана, я думаю, что у вас будет своего рода зацикливание, и вы будете создавать только новые переменные, но ранее использованные переменные также будут присутствовать в памяти, поскольку их ссылка все еще существует.

Поэтому попробуйте удалить их ссылочные переменные. Затем, когда память будет почти заполнена, Java Garbage Collector автоматически вступит в игру и освободит вашу память для вас.

person Community    schedule 27.01.2012
comment
Что вы подразумеваете под удалением ссылочных переменных? Основываясь на коде, который я только что опубликовал, поскольку я вызываю метод getScreenShot() и передаю его в качестве параметра другому методу, я думаю, что все переменные в методе getScreenShot(), а также созданный объект BufferedImage будут разыменован ... этого достаточно, чтобы разыменовать его? Или вы имеете в виду что-то другое? - person Paul; 27.01.2012
comment
@Paul Я думаю, что проблемы находятся в вашем разделе цикла while, вы создаете объекты изображения IIOImage на каждой итерации. Таким образом, он будет продолжать добавлять новые переменные вместе с ранее использованными переменными. Попробуйте использовать только одну переменную (объявив IIOImage вне цикла). - person gprathour; 27.01.2012

arrow_upward
1
arrow_downward

Да, когда использование переменной завершено, скажите сборщику мусора, что она больше не используется. Вы можете сказать это, сославшись на объект как на null.

В вашем случае после этой строки

writer.write(null, image, iwp);

попробуйте добавить эту строку

image=null;
person Jayy    schedule 27.01.2012
comment
Какой размер кучи указан по умолчанию? Я предполагаю, что ваша максимальная куча позволяет только один скриншот данных. С вашим текущим кодом в данный момент времени у вас будет 2 данных скриншотов. - person Jayy; 27.01.2012