EDIT #2 - これは過度の最適化である可能性があり、問題が発生するまで Robot クラスをそのまま使用しようとしましたが、FWIW:
私は、短いCPUスパイク/過負荷のために動作を停止してはならないオーディオソフトウェアを含む、非常にCPUとメモリを集中的に使用するソフトウェアと一緒に実行されるアプリケーション(厳密にはOSX Lion用)を設計しています。ほとんどのオーディオ ソフトウェアと同様に、メモリは常に読み書きされています。
createScreenCapture
これは非常に軽量なアプリケーションです。主な目的は、Robot クラスのメソッドを使用して、最大数時間の間、毎分数回のスクリーン キャプチャを取得することです。
後続の各スクリーン キャプチャでは、前のスクリーン キャプチャは必要ありません。Robot のソース コードを見ると、呼び出されるBufferedImage
たびに新しいものが作成されているように見えますcreateScreenCapture()
。これは、前のものがガベージ コレクションのために残されていることを意味しますね。
私はJavaとガベージコレクターが初めてです。これらの古いキャプチャを管理/削除する GC の必要性によって引き起こされる CPU スパイクが心配です。理想的には、イメージが画面から直接移動して、毎回メモリ内の同じ領域を上書きでき、アプリケーションのメモリ フットプリントは、GC が過度に機能しなくてもかなり一定に保たれます。
createScreenCapture()
同じ静的 BufferedImage を使用するように、Robot クラスを拡張してオーバーライドすることをお勧めしますか? これが機能する場合、ロボットがキャプチャごとに新しいメモリを割り当てる現在の方法では、誰にとってもメリットがないと思います。
ありがとう。
EDIT #1 - hereから取得した関連するロボットのソース コードを以下に示します。毎回新しい 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;
}