表題のとおりソケット通信を行って、画面のスクリーンキャプチャをクライアントPCに送信するプログラムを考えています。それで、java.awt.Robotを使用することで画面のキャプチャをすることに成功しクライアントPCへ送信することにも成功したのですが、実はプログラムを立ち上げてから5,6回キャプチャ送信をするとjava.lang.OutOfMemoryErrorというエラーが発生しそれ以上送信することが出来なくなってしまいます。
なんとかどの部分でエラーが発生しているかは突き止めたのですが、そのエラーが発生する原因がどうしてもわかりません。JAVAを始めたばかりなので、もしかしたらエラーの発生部分も違うのかもしれませんが、どうかご教示ください。よろしくお願いいたします。
以下はエラーの発生するクラスです(エラー発生箇所にコメントを入れています)。
このクラスのgetScreen()メソッドを外部から呼び出すことでImageIconを取得しています。取得したImageIconはobjectInputStreamとobjectOutputStreamを使ったソケットを通してクライアントに送信しています。
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
public class KCapture {
private Robot rb;
private Image im;
private Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private ImageIcon ii = new ImageIcon();
private Rectangle rc = new Rectangle(0,0,screenSize.width,screenSize.height);
public void KCapture(){
}
public void makeRobot(){
try{
rb = new Robot();
}
catch (AWTException awte){newJTF.setText(n+awte.toString());}
}
public ImageIcon getScreen(){
ii = new ImageIcon(((Image)rb.createScreenCapture(rc)));
//この一行上でjava.lang.OutOfMemoryErrorが発生します。
return ii;
}
}
No.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/ …
ただ「repaint()」は例外で、他のスレッドからも使えます。
だから、setIcon()を使わず、paintComponet()の中でdrawImage()を使って描画を行い、
更新はrepaint()で行うようにしてみたらどうでしょう。
それでだめなら、Imageの使用をやめてBufferedImageを使ってみるとか…。
(↑これは根拠のある意見ではありませんが、
ただのImageよりもBufferedImageの方が、普通の意味の「画像データ」に
近いと思うので)
あと、細かいことを言うと、上のwhile文の中で変数iiの使用は
必要がないので、できれば消した方がよいでしょう。
このコードには省略があって、実際には必要だという場合はすみません。
参考URL:http://java.sun.com/docs/books/tutorial/uiswing/ …
No.1
- 回答日時:
前に生成した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){
}
」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」」
書いてみて自分でも非常にわかりづらい説明のような気がします。
もうしわけありません。もし、不明な点、怪しい点などがございましたら
ご指摘ください。よろしくお願いいたします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- C言語・C++・C# C# DatagridviewにExcelシートを反映するとエラーが出る 2 2023/05/06 17:12
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- C言語・C++・C# PC画面を録画するプログラムでdllの読み込みエラー 1 2023/04/22 08:31
- C言語・C++・C# C# で、あるフォルダー内にあるすべてのテキストファイルを別のフォルダーにコピーする。 4 2022/11/21 13:23
- JavaScript 入力フォームの javascript で メールアドレスの正規チェックをを行い、ボタンをクリックして 2 2022/04/27 16:06
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- Excel(エクセル) EXCELの外部データ取得ができない 1 2023/03/23 09:03
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「タイプ初期化子が例外をスロ...
-
連続する「\\」をひとつの「\\...
-
文字列が数字のみで構成されて...
-
VB.NETで16進数が正しいかどう...
-
XMLパーサの種類について混乱し...
-
【JAVA】与えられた金額を貨幣...
-
CreateEventについて
-
Javaの例外 IllegalArgumentExc...
-
Timestamp型への変換について(J...
-
nullで、return出来るのはどん...
-
VB.Net Object型 空かどうか
-
例外ってIf文の中に入れますか...
-
SQLです教えてくださいお願いし...
-
エクセルVBAで、条件に一致する...
-
オブジェクト指向プログラミン...
-
インスタンス参照でアクセスで...
-
VBAでの[]
-
private static という変数の修飾
-
レコード件数の表示
-
生成したインスタンスを削除す...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「タイプ初期化子が例外をスロ...
-
【JAVA】与えられた金額を貨幣...
-
連続する「\\」をひとつの「\\...
-
文字列からダブルクオートの削除
-
VB.Net Object型 空かどうか
-
0除算の例外処理ができない!!...
-
VB.NETで16進数が正しいかどう...
-
数字か文字列かを判定する関数
-
例外ってIf文の中に入れますか...
-
C# マルチスレッドにおける例外...
-
スタックオーバーフローとは?
-
String型の日付(2005/11/25)の...
-
Timestamp型への変換について(J...
-
C# UriFormatExceptionの回避
-
VBA Evaluate関数 型が一致しま...
-
ADOによるレコードの追加/更新
-
時間の取得
-
WebClient()以外でネットにアク...
-
C#の捕捉されない例外処理の対...
-
タトゥーや墨を入れる人の共通点
おすすめ情報