- ベストアンサー
スクリーンキャプチャ画面のソケット通信でメモリエラー??
- Javaで画面のスクリーンキャプチャをクライアントPCに送信するプログラムを作成した際、実行中にjava.lang.OutOfMemoryErrorが発生する問題が発生しています。
- エラーの発生箇所は、getScreen()メソッド内の一行で、rb.createScreenCapture(rc)の処理を実行する際にエラーが発生します。
- プログラムを立ち上げてから5,6回キャプチャ送信をするとエラーが発生し、それ以上の送信ができなくなります。エラーの原因を突き止めることができず、ご教示をお願いします。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
ん~~。わかんない。 スレッド関係にはあんまり自信がないので…。 (もっとも「スレッドには自信がある!」という人は世の中にそんなにいないと思う) ただ、もしかしたら、 //入力監視を行います。 while(true){ ii = (ImageIcon)iStream.readObject(); newJL.setIcon(ii); ii=null; } のnewJL.setIcon(ii);ところかなあ…。 というのは、これは独自に作ったスレッドからnewJL(JLabelですよね)の setIconメソッドを使っているけど、 Swingコンポーネントのメソッドはほとんどスレッドセーフではありません。 つまり勝手に別のスレッドから使っちゃいけないことになっているのです。 http://java.sun.com/docs/books/tutorial/uiswing/overview/threads.html ただ「repaint()」は例外で、他のスレッドからも使えます。 だから、setIcon()を使わず、paintComponet()の中でdrawImage()を使って描画を行い、 更新はrepaint()で行うようにしてみたらどうでしょう。 それでだめなら、Imageの使用をやめてBufferedImageを使ってみるとか…。 (↑これは根拠のある意見ではありませんが、 ただのImageよりもBufferedImageの方が、普通の意味の「画像データ」に 近いと思うので) あと、細かいことを言うと、上のwhile文の中で変数iiの使用は 必要がないので、できれば消した方がよいでしょう。 このコードには省略があって、実際には必要だという場合はすみません。
その他の回答 (1)
- liar_adan
- ベストアンサー率48% (730/1515)
前に生成したImageIconが、ガベージコレクションに回収されないで メモリを圧迫しているのだと思われます。 上記のコード上だとiiは上書きされますが、getScreen()の返り値を使う側で オブジェクトを殺してやらないと、ずっと残ってしまいます。 たとえば AClass a, b; a = new AClass(); b = a; として、 a = null; としても、作ったオブジェクト自体は解放されません。(bが参照を保持してるから) ImageIconを使用する側のどこかに、参照が生きたままのところがあるのではないでしょうか。 なんとなく「ソケットを通して送信」の部分が怪しいように感じます。
お礼
ありがとうございす。非常に参考になりました!! それで、ご指摘いただいたとおりガーベッジコレクションの拾えていない部分というのを自分なりに検討してみたのですが、どうもliar_adanさんの仰るとおり「ソケットを通して送信」の部分が怪しいような気がしています。 プログラムの流れは以下のようになっているのですが、まだエラーの原因がどうしてもよくわかりません。多分ストリームの記述方法に何か誤りがあるのではないかと勝手に思っているのですが、、、 何度も申し訳ありませんが、この部分でもし「これはおかしいだろ!」というような箇所があればご指摘いただけると幸いです。どうかよろしくお願いいたします。 」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」 プログラムはJBuilder7Personalで作成しています。 クラスは4つから作成されていて一つ目はJbuilderが最初 に作るmain()のあるApplication1のクラス。 二つ目はmain()から呼び出されるGUIを定義しているFrame1の クラス。 三つ目は先日の質問でも書かせていただいたクラスでKCaptureクラス (これはスクリーンキャプチャを取得するクラスです)。 最後の4つ目がFrame1でソケット通信を行うためクライアント(サーバ) のソケットを取得するthreadクラスです。 まずスクリーンキャプチャを送信する流れで最初に呼び出されるのは KCaptureクラスのgetScreen()クラスで、これは先日の質問で書かせて いただいたとおりです。 次にgetSceenの呼び出し下のFrame1では「送信」ボタンを押すと次の プログラムが呼び出されます。 //(1)Frame1内の記述です。 ii = k.getScreen(); oStream.writeObject(ii); oStream.flush(); ii =null; //oStreamは //private ObjectOutputStream oStream; //Frame1のウィンドウオープン時にThreadクラスのgetOStream() //を呼び出して取得しています。 --------------------------------------------------------------------- //(2)次にthread内の記述です。 public ObjectOutputStream getOStream(){ return oStream; } //Frame1からウィンドウオープン時に呼び出してFrame1のJLabelを //newJLに参照渡しします。 public void setLabel(JLabel jl){ newJL = jl; } public void run(){ try{ servsock = new ServerSocket(3333); sock = servsock.accept(); oStream = new ObjectOutputStream(sock.getOutputStream()); iStream = new ObjectInputStream(sock.getInputStream()); //入力監視を行います。 while(true){ ii = (ImageIcon)iStream.readObject(); newJL.setIcon(ii); ii=null; } } catch(Exception ee){ } 」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」 書いてみて自分でも非常にわかりづらい説明のような気がします。 もうしわけありません。もし、不明な点、怪しい点などがございましたら ご指摘ください。よろしくお願いいたします。