スクリーンキャプチャ画面のソケット通信でメモリエラー??

このQ&Aのポイント
  • Javaで画面のスクリーンキャプチャをクライアントPCに送信するプログラムを作成した際、実行中にjava.lang.OutOfMemoryErrorが発生する問題が発生しています。
  • エラーの発生箇所は、getScreen()メソッド内の一行で、rb.createScreenCapture(rc)の処理を実行する際にエラーが発生します。
  • プログラムを立ち上げてから5,6回キャプチャ送信をするとエラーが発生し、それ以上の送信ができなくなります。エラーの原因を突き止めることができず、ご教示をお願いします。
回答を見る
  • ベストアンサー

スクリーンキャプチャ画面のソケット通信でメモリエラー??

表題のとおりソケット通信を行って、画面のスクリーンキャプチャをクライアント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; } }

  • Java
  • 回答数2
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • liar_adan
  • ベストアンサー率48% (730/1515)
回答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/overview/threads.html ただ「repaint()」は例外で、他のスレッドからも使えます。 だから、setIcon()を使わず、paintComponet()の中でdrawImage()を使って描画を行い、 更新はrepaint()で行うようにしてみたらどうでしょう。 それでだめなら、Imageの使用をやめてBufferedImageを使ってみるとか…。 (↑これは根拠のある意見ではありませんが、 ただのImageよりもBufferedImageの方が、普通の意味の「画像データ」に 近いと思うので) あと、細かいことを言うと、上のwhile文の中で変数iiの使用は 必要がないので、できれば消した方がよいでしょう。 このコードには省略があって、実際には必要だという場合はすみません。

参考URL:
http://java.sun.com/docs/books/tutorial/uiswing/overview/threads.html

その他の回答 (1)

  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.1

前に生成したImageIconが、ガベージコレクションに回収されないで メモリを圧迫しているのだと思われます。 上記のコード上だとiiは上書きされますが、getScreen()の返り値を使う側で オブジェクトを殺してやらないと、ずっと残ってしまいます。 たとえば AClass a, b; a = new AClass(); b = a; として、 a = null; としても、作ったオブジェクト自体は解放されません。(bが参照を保持してるから) ImageIconを使用する側のどこかに、参照が生きたままのところがあるのではないでしょうか。 なんとなく「ソケットを通して送信」の部分が怪しいように感じます。

kuwasato
質問者

お礼

ありがとうございす。非常に参考になりました!! それで、ご指摘いただいたとおりガーベッジコレクションの拾えていない部分というのを自分なりに検討してみたのですが、どうも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

  • javaでスタート画面を作っていて困っています。

    現在javaでゲームのスタート画面を作っているのですが、パネルが透過されずに困っています。 プログラムソースは import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; import javax.swing.ImageIcon; import java.awt.Container; import java.awt.BorderLayout; import javax.swing.*; import java.awt.Font; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.*; import java.awt.event.*; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; import javax.swing.ImageIcon; import java.awt.Container; import java.awt.BorderLayout; import javax.swing.border.LineBorder; import javax.swing.border.EtchedBorder; import java.awt.Color; import java.awt.Container; class Start最新版 extends JFrame{ public static void main(String args[]){ Start最新版 frame = new Start最新版("タイトル"); frame.setVisible(true); } Start最新版(String title){ setTitle(title); setBounds(10, 10, 1024, 768); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel p = new JPanel(); p.setOpaque( false ); ImageIcon icon1 = new ImageIcon("Start.jpg"); JLabel label1 = new JLabel(icon1); JLabel label2 = new JLabel(); p.add(label1); Container contentPane = getContentPane(); contentPane.add(p, BorderLayout.CENTER); JButton button1 = new JButton("ゲームを始める"); button1.setFont(new Font("Mairyo", Font.PLAIN, 30)); JPanel n = new JPanel(); n.setOpaque(false); n.setLayout(new BoxLayout(n, BoxLayout.Y_AXIS)); n.add(Box.createRigidArea(new Dimension(290,30))); n.add(button1); となっています。「ゲームを始める」ボタンだけを残して、周りのパネルを透過して画像を表示させたいのですが、うまくいきません!解決方法をご存知の方どうか教えていただきたいです!よろしくお願いします。

  • JButtonの画像をactionPerformedメソッド内で再描画

    JButtonの画像をactionPerformedメソッド内で再描画したい。 以下のソースのようにして、再描画したいのです。 setIconメソッドではなく、 JButtonに対して描画したものに対して再描画したいです。 Graphics2DクラスについてJAVA APIで調べましたが、 仕組の理解に至りませんでした。 仕組みと方法を教えて頂きたいです。 よろしくお願いいたします。 import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; public class test extends JFrame implements ActionListener{ JButton b= new JButton(); public static void main(String a[]) { new test(); } public test() { super(); this.setSize(100,100); b.addActionListener(this); b.add(new Zoom(new ImageIcon("img1.jpg"),0,0,50,50)); this.add(b); this.setVisible(true); } class Zoom extends JComponent { private static final long serialVersionUID = 1L; private ImageIcon icon = null; private int x = 0; private int y = 0; private int h = 0; private int w = 0; private double scale = 1.0d; public Zoom(ImageIcon icon, int x, int y, int w, int h) { super(); this.icon = icon; this.x = x; this.y = y; this.w = w; this.h = h; } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.scale(scale, scale); ////////////////////////////////// //画僧を再描画したい。 //g2.clearRect(0, 0, 80, 80);//× g2.drawImage(icon.getImage(), x, y, w, h, this); } } public void actionPerformed(ActionEvent e) { if(e.getSource()==b){ System.out.print("ok"); //this.repaint();//× //b.repaint();//× b.add(new Zoom(new ImageIcon("img2.jpg"),0,0,50,50));//(再描画できない) //b.setIcon(new ImageIcon("img2.jpg"));//ok(再描画出来る) } } }

    • ベストアンサー
    • Java
  • JButtonの座標(0,0)にアイコンをセット

    JButtonに以下のように、画像を書込む際、画像を一番は端(左上角)から乗せたいです。 つまり、ボタンの右上角(0,0)から乗せたいのです。 現状では、左端に隙間があいてしまいます。 この方法がご存知の方がおられましたら教えてください。 よろしくお願いいたします。 import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; public class Zoom extends JComponent { private static final long serialVersionUID = 1L; private ImageIcon icon = null; private int x = 0; private int y = 0; private int h = 0; private int w = 0; private double scale = 1.0d; public Zoom(ImageIcon icon, int x, int y, int w, int h) { super(); this.icon = icon; this.x = x; this.y = y; this.w = w; this.h = h; } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.scale(scale, scale); g2.drawImage(icon.getImage(), x, y, w, h, this); } public static void main(String[] args) { ImageIcon icon = new ImageIcon("cherry.jpg"); Zoom zoom = new Zoom(icon,0,0,100,100); JButton b = new JButton(); JFrame f = new JFrame(); b.add(zoom); b.setPreferredSize(new Dimension(icon.getIconHeight(), icon.getIconWidth())); f.add(b); f.pack(); f.setVisible(true); } }

    • ベストアンサー
    • Java
  • プログラムの実行順番を教えてください

    始めまして。 http://javagame.skr.jp/index.php?RPG%A4%F2%BA%EE%A4%ED%A4%A6のページで配布されているサンプルソースの順番がわからないので教えてください。 できれば、実行順番に番号を振ってもらえればありがたいです。 ○Rpg.class import java.awt.Container; import javax.swing.JFrame; /* * Created on 2005/10/09 * */ /** * @author mori * */ public class Rpg extends JFrame { public Rpg() { // タイトルを設定 setTitle("勇者登場"); // パネルを作成 MainPanel panel = new MainPanel(); Container contentPane = getContentPane(); contentPane.add(panel); // パネルサイズに合わせてフレームサイズを自動設定 pack(); } public static void main(String[] args) { Rpg frame = new Rpg(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } ○MainPanel.class import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import javax.swing.ImageIcon; import javax.swing.JPanel; class MainPanel extends JPanel { // パネルサイズ private static final int WIDTH = 480; private static final int HEIGHT = 480; // 勇者のイメージ private Image heroImage; public MainPanel() { // パネルの推奨サイズを設定 setPreferredSize(new Dimension(WIDTH, HEIGHT)); // イメージをロード loadImage(); } public void paintComponent(Graphics g) { super.paintComponent(g); // 勇者のイメージを表示 g.drawImage(heroImage, 0, 0, this); } private void loadImage() { ImageIcon icon = new ImageIcon(getClass().getResource("image/hero.gif")); heroImage = icon.getImage(); } }

  • tabにdrawImageで画像を描画したい

    tabにdrawImageで画像を描画したい 以下のソースでtabbedpaneに対して、ImageIconを指定して画像をのせるではなく、 drawImageメソッドで描画したいです。 ご存知の方がおられましたら教えてください。 import javax.swing.*; import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.Graphics2D; public class JTabbedPaneTest4 extends JFrame { Zoom zoom = null; public static void main(String[] args) { JTabbedPaneTest4 frame = new JTabbedPaneTest4(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setVisible(true); } JTabbedPaneTest4() { JTabbedPane tabbedpane = new JTabbedPane(); JPanel tabPanel1 = new JPanel(); tabPanel1.add(new JButton("button1")); ImageIcon icon1 = new ImageIcon("img1.jpg"); zoom = new Zoom(icon1, 0, 0, 50, 50); //tabbedpane.addTab("tab1", icon1, tabPanel1);//ok //tabbedpane.add(zoom, tabPanel1);//ng(パネルに書き込まれてしまう) getContentPane().add(tabbedpane, BorderLayout.CENTER); } class Zoom extends JComponent { private static final long serialVersionUID = 1L; private ImageIcon icon = null; private int x = 0; private int y = 0; private int h = 0; private int w = 0; private double scale = 1.0d; public Zoom(ImageIcon icon, int x, int y, int w, int h) { super(); this.icon = icon; this.x = x; this.y = y; this.w = w; this.h = h; } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.scale(scale, scale); g2.drawImage(icon.getImage(), x, y, w, h, this); } } }

    • ベストアンサー
    • Java
  • Jave Swing 画像表示わからない

    java swingでGUIをプログラミングしている者です。 JLabelにImageIconの画像を貼り付けるプログラムです。↓ //画像を表示するプログラム //インポート import javax.swing.*; import java.awt.*; import java.awt.event.*; class gazopro extends JFrame{ JLabel l1; JButton b1; JPanel p; public static void main(String args[]) { //ウィンドウを作成また設定 gazopro frame = new gazopro(); frame.setBounds(300,200,700,400); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } gazopro(){ //コンポーネントを作成 p = new JPanel(); add(p); b1 = new JButton("画像を表示"); p.add(b1); ImageIcon icon = new ImageIcon("image.jpg"); l1 = new JLabel(icon); p.add(l1); } }   わからないところは、ImageIcon icon = new ImageIcon("image.jpg");のところです。 ImageIconの引数は、プログラミングを行っているパソコン(OS は Windows)のマイコンピューター→ Cドライブ→ MyJava→ image.jpgを指定しましたがこれで合ってますか? このプログラムでは、画像が表示されませんでした。 どうすればいいでしょうか? 解説と、ご指導宜しくお願いします。

    • ベストアンサー
    • Java
  • javaで作成したゲーム→android用に変換

    お世話になっています。 前回こちらで、 1~25までの順番にタッチしていくというゲームのjavaのソースコードを教えて頂きました。 今回お聞きしたい内容が そのゲームに (1)秒単位のタイマーを付け、25個目の数字を押したらカウント終了 (2)androidアプリとして使用できるように変換 としようとしているのですが、いろいろと変換しなければいけないみたいで、 どちらもなかなかうまくいきません。 前回教えて頂いたコード import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; class MainFrame extends JFrame { private static final long serialVersionUID = 1L; private List<NumberdButton> numbers = new ArrayList<NumberdButton>(); private GridLayout grid = new GridLayout(5, 5); private boolean[] pressed = new boolean[5 * 5 + 1]; public MainFrame(String name) { super(name); setResizable(false); } public void setButtons(final Container pane) { initPressed(); initNumbers(); final JPanel p = new JPanel(grid); for (final NumberdButton b : numbers) { p.add(b); b.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (pressed[b.getNumber() - 1]) { b.setIcon(new ImageIcon("" + numbers + "_off.png")); b.setEnabled(false); pressed[b.getNumber()] = true; } } }); } pane.add(p, BorderLayout.CENTER); } private void initNumbers() { for (int i = 1; i < 26; i++) { numbers.add(new NumberdButton(i)); } Collections.shuffle(numbers); } private void initPressed() { for (int i = 0; i < pressed.length; i++) pressed[i] = false; pressed[0] = true; } public static void create(String name) { MainFrame frame = new MainFrame(name); frame.setDefaultCloseOperation(EXIT_ON_CLOSE); frame.setButtons(frame.getContentPane()); frame.pack(); frame.setVisible(true); } } class NumberdButton extends JButton { private static final long serialVersionUID = 1L; private final int number; public NumberdButton(int number) { super(new ImageIcon("" + number + ".png")); this.number = number; } public int getNumber() { return number; } } public class pressbuttontoorder { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { MainFrame.create("PressButtonToOrder"); } }); } } androidのレイアウトはTableLayoutとtableRowでボタンを配置すればいいのかなと思い 配置しました。 TableLayout <TableRow1 <Button1~5 <TableRow2 <Button6~10 という風に25個ボタンを配置しています。 行き詰まっております。 どなたかやり方やコード等、教えて頂けたらありがたいです。 ご教授よろしくお願いします。

    • ベストアンサー
    • Java
  • java applet

    import java. applet.*; import java. awt. Button; import java. awt. Label; import java. awt. TextField; import java. awt. event.*; public class 1120 extends Applet implements ActionListener { private TextField box1 = new TextField(5); private TextField box2 = new TextField(5); private TextField box3 = new TextField(5); private Label moji1 = new Label(" と "); private Label moji2 = new Label(" の和は "); private Label moji3 = new Label(" である。 "); private Button ok = new Button("OK"); public void init() { resize( 320 , 240); add( box1 ); add( moji1 ); add( box2 ); add( moji2 ); add( box3 ); add( moji3 ); add( ok ); ok.addActionListener( this ); } public void actionPerformed( ActionEvent e ) { int i=0 ,j =0 , k; String t1 = box1.getText(); String t2 = box2.getText(); i = Integer.parseInt( t1 ); j = Integer.parseInt( t2 ); k = i + j; String s = Integer.toString( k ); box3. setText( s ); } } //上記のプログラムを書いたのですが、なぜかエラーが出てしまいます。勿論、自分でも見直しましたが、その理由がわかりませんでした。知識のある方、ご回答の方お願いします。

  • setIcon() の反対のようなものを探しています。

    こんばんは。GUIで、一秒ごとに画像を切り替える、スライドショーのようなものを作ってみたのですが、画像が切り替わらず、画像の上に画像が配置され、どんどん積み重なっていく感じになりました。以下がそのコードです。 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class IconChange extends JFrame{ private Timer timer; private JLabel img; private int sec; private Icon[] icon=new ImageIcon[11]; private JPanel pane; public static void main(String[] args){ IconChange frame=new IconChange("画像チェンジ"); frame.pack(); frame.setDefaultCloseOperation(3); frame.setVisible(true); } public IconChange(String title){ super(title); sec = 0; pane=(JPanel)getContentPane(); pane.setPreferredSize(new Dimension(800,600)); pane.setOpaque(true); pane.setBackground(new Color(0x00000000, true)); img=new JLabel(new ImageIcon("images2/1.jpg")); pane.add(img); for(int i=0;i<=10;i++){ icon[i]=new ImageIcon("images2/"+i+".png"); } timer = new Timer(1000 , new Kirikae()); timer.start(); } class Kirikae implements ActionListener{ public void actionPerformed(ActionEvent e){ img.setIcon(icon[sec]); if(sec>=10){sec=0;} sec++; } } } JLabelに画像をセットしたら、前の画像と入れ替わり新しい画像がセットされるとおもったのですが、前の画像が残ったまま新しい画像がセットされます。新しい画像をセットする前に前の画像のセットを取り消したいのですが、いい方法がございましたらアドバイスお願いいたします。

    • ベストアンサー
    • Java
  • 整数を好きなだけ入力し、個数、合計、平均値を表示するプログラム

    appletviewerに、ボックスの中に整数を好きなだけ入力し、個数、合計、平均値を以下のように表示させるようなプログラムを作りたいです。(1,2,3を入力した場合)     データ□ (入力)        (計算)   個数=3   合計=6   平均値=2 ※□はボックスです。(入力)(計算)はクリックするボタンです。 どなたかご指導やアドバイスをお願いいたします。まだまだ初心者でとても困っています。。 ちなみに途中まで考えたのが以下のプログラムです。 import java.applet.*; import java.awt.Button; import java.awt.Label; import java.awt.TextField; import java.awt.event.*; public class Lec1106 extends Applet implements ActionListener { private TextField box1 = new TextField(5); private Label moji1 = new Label("データ"); private Label moji2 = new Label("個数="); private Label moji3 = new Label("合計="); private Label moji4 = new Label("平均値="); private Button nyuuryoku = new Button("入力"); private Button keisan = new Button("計算"); public void init() { resize(320,240); add(moji1); add(box1); add(nyuuryoku); nyuuryoku.addActionListener(this); add(keisan); keisan.addActionListener(this); add(moji2); add(moji3); add(moji4); } public void actionPerformed(ActionEvent e)  {int i; String t1=box1.getText(); i=Integer.parseInt(t1);

    • ベストアンサー
    • Java

専門家に質問してみよう