РЕДАКТИРОВАТЬ # 2 - я решил, что это может быть чрезмерной оптимизации и будет пытаться использовать класс Robot, как есть, пока я не столкнусь с проблемами, но FWIW:
Я разрабатываю приложение (строго для OSX Lion), которое работает вместе с некоторым программным обеспечением, требующим значительных ресурсов процессора и памяти, включая программное обеспечение для работы со звуком, которое не должно прерывать его работу из-за коротких скачков / перегрузок процессора. Как и большинство аудио программ, память постоянно читается / записывается.
Это очень легкое приложение - его основная цель - делать несколько снимков экрана каждую минуту в течение нескольких часов, используя метод createScreenCapture
класса Robot.
При каждом последующем снимке экрана предыдущий снимок не требуется. После просмотра исходного кода робота выясняется, что каждый раз при вызове createScreenCapture()
создается новый BufferedImage
, что означает, что предыдущий оставлен для сборки мусора, верно?
Я новичок в Java и сборщике мусора. Я обеспокоен скачками ЦП, вызванными необходимостью GC управлять / удалять эти старые записи. В идеале, изображение может идти прямо с экрана, чтобы каждый раз перезаписывать одну и ту же область в памяти, и объем памяти приложения останется довольно постоянным, если ГХ не будет работать слишком много.
Желательно ли / возможно ли попытаться расширить класс Robot и переопределить createScreenCapture()
, чтобы он использовал тот же статический BufferedImage? Если бы это сработало, я бы не увидел ни одного преимущества для нынешнего способа, которым робот распределяет новую память для каждого захвата.
Спасибо.
EDIT # 1 - соответствующий исходный код робота, взятый из здесь , находится ниже. Похоже, что каждый раз создается не только новый BufferedImage, но также одинаково большие int [], DataBufferInt и WritableRaster. Кроме того, все издержки создаются peer.getRGBPixels (), который, похоже, подключается к графическому драйверу, но я не могу найти источник или информацию по этому вопросу. Я ошибаюсь, думая, что расточительно не использовать одну и ту же память? Понятно, что использование статических указателей ничего не решит. BufferedImage нужно будет перезаписать, используя свои собственные методы set. Я добавил свои собственные комментарии к подходу для этого, помеченный $$$. Теоретически это сэкономило бы много действий GC для моего приложения, но стоит ли беспокоиться об этом? Если бы я знал больше о Java и профилировании, я бы получил право попробовать все это.
public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
checkScreenCaptureAllowed();
// according to the spec, screenRect is relative to robot's GD
Rectangle translatedRect = new Rectangle(screenRect);
translatedRect.translate(gdLoc.x, gdLoc.y);
checkValidRect(translatedRect);
BufferedImage image;
DataBufferInt buffer;
WritableRaster raster;
if (screenCapCM == null) {
/*
* Fix for 4285201
* Create a DirectColorModel equivalent to the default RGB ColorModel,
* except with no Alpha component.
*/
screenCapCM = new DirectColorModel(24,
/* red mask */ 0x00FF0000,
/* green mask */ 0x0000FF00,
/* blue mask */ 0x000000FF);
}
// need to sync the toolkit prior to grabbing the pixels since in some
// cases rendering to the screen may be delayed
Toolkit.getDefaultToolkit().sync();
int pixels[]; //$$$ do away with this array altogether?
int[] bandmasks = new int[3];
pixels = peer.getRGBPixels(translatedRect); //$$$ not needed
buffer = new DataBufferInt(pixels, pixels.length); //$$$ not needed
bandmasks[0] = screenCapCM.getRedMask();
bandmasks[1] = screenCapCM.getGreenMask();
bandmasks[2] = screenCapCM.getBlueMask();
raster = Raster.createPackedRaster(buffer, translatedRect.width, translatedRect.height, translatedRect.width, bandmasks, null);
//$$$ not needed
//$$$ i don't know what bandmasks are, but maybe the full-size raster could be initialized once with the bandmasks array, then...
//$$$ ...use raster.setPixels(0, 0, translatedRect.width, translatedRect.height, peer.getRGBPixels(translatedRect));
image = new BufferedImage(screenCapCM, raster, false, null);
//$$$ instead use image.setData(raster);
CachingSurfaceManager.restoreLocalAcceleration(image);
return image;
}