Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

Out Of Memoey

以前、本掲示板にて、画像をsocketから取得して画面表示させるところをご指南いただき、映像を表示させることができた
ありがとうございました。
しかし、何時間も連続で画像を取得・表示するとそのうちOut Of Memoryでストップしてしまいます。
色々調べてみたものの解決できません。
(jconsoleでメモリーで調べましたが、プログラムを少しづつ削っていくと結局、画像を繰り返して表示させるところでメモリーのクランチが発生することが判明いたしました)

画像は永遠に表示させたく、何卒ご教示ください。
よろしくお願いいたします。


以下ソース抜粋です。


class ImageGet extends Thread {//
   public static BufferedImage imagex;
   public Graphics2D g2D;
     
        public ImageGet(int d){
         getno = d;
        }
        
   public void run() {//run
           ・
      途中省略
           ・
      JFrame frame = new JFrame("画像表示");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(new Dimension(648, 514));
      
      while (loop !=-1 ) {//
      ・
        画像読み込みルーチン(省略)
            ・  
         ImageDraw ih =new ImageDraw();
         bais.close();
         frame.add(ih,BorderLayout.CENTER);
         frame.setVisible(true);
              ・
           途中省略
              ・
    }//while loopで表示を繰り返す
}//run()

class ImageDraw extends JPanel{
    public void ImageDraw(final byte imx) {
           setBackground(Color.black);
           imagex=new BufferedImage(640,480,BufferedImage.TYPE_INT_RGB);
           g2D = imagex.createGraphics();
    }
    protected void paintComponent(final Graphics g) {
           super.paintComponent(g);
           final Graphics2D g2D = (Graphics2D)g;
           g2D.drawImage(imagex,0,0,640,480,this);
      }
    public void main(final String args[]) {
           //System.out.println("画像表示");
    }
}//class ImageDraw
}//class ImageGet

42

回答

8973

閲覧

42件の回答

評価

0

Out of Memoryがどういうもので、なぜ起きるのかは理解してるのか?

>色々調べてみたものの
こんな一文じゃ、ほんとに調べたのか怪しいものだ。

評価

0

>結局、画像を繰り返して表示させるところで
>メモリーのクランチが発生することが判明いたしました

いい線行ってるんじゃない。
が、ここで止まったのが惜しい。
$氏も書いているが、
次は、何故これがメモリオーバーにつながるのか、考えませう。

評価

0

ご指摘ありがとうございます。

初めからメモリー不足によるものだろうと勝手に素人の憶測で判断し、メモリー割当を変えて何度も実験しましたが、結局は改善できませんでした。

次に、原因を残りのプログラムのミスに焦点をしぼりましたが、その中で、SWINGがシングルスレッド・・・イベントディスパッチ・・・EDT・・・この辺りが関連してる感じです。

まずは、中間報告いたします。

評価

0

メモリ不足はなぜ起こるのか?
大量のデータをいちどきに処理する関係で、メモリが足りなくなるわけだ。
翻って、あなたのプログラムはそんなに大量のデータをいちどきに処理するものか?

評価

0

>翻って、あなたのプログラムはそんなに大量のデータをいちどきに処理するものか?

50Kbyte程度の画像を1秒間に30枚程度連続して取得・表示させたいと考えております。
最初は、プログラムミス?からフレームも新しいのができて80フレームぐらいでOUT OF MEMORY がでてきましたが、現状は、1フレーム(JFrame)だけで表示し、秒10枚、6時間程度表示が可能となりました。
しかし、この6時間辺りから処理が2秒1枚程度に急激に減速してしまい、以降どんどん処理が遅くなります。
ネットワークから画像が来る限り、24時間365日エンドレスで表示させたいのです。

素人考えで、パソコンでテレビの録画ができるボードとソフトが販売してあり、単純に同等の処理ができるのかな?と思ってやっております。(プログラム初心者6ヶ月の浅はかな考えかも・・・)

根本的に間違いでしょうか?

評価

0

>現状は、1フレーム(JFrame)だけで表示し、秒10枚、6時間程度表示が可能

216,000枚か。1枚50Kとして、
画像データだけで、10.8Gになるけど、
これ全部、インスタンスとして持ってるの?

評価

0

いつもご指導ありがとうございます。

以下でイメージ取得→画像表示を繰り返しており、new ImageDraw();の部分で画像表示のインスタンスを作っていると思います。(他にも画像と関係ないところでも同じ回数インスタンスを沢山作っていますが、これが原因でメモリーアウトにはなりませんでした)

これが6時間分メモリーに溜まってる???そういえば、jconsoleで10Mのところで一生懸命乱高下しておりましたが・・・まだ飲み込めません。


以下繰り返される部分

imagex=ImageIO.read(bais);//配列ストリームからBufferedImageをゲット。→Imageへ
ImageDraw ih =new ImageDraw();//画像表示部

bais.close();

frame.add(ih,BorderLayout.CENTER);
frame.setVisible(true);

評価

0

addするばっかりでremoveしてないの?
そりゃパンクもするんじゃない。

removeすれば、動作は変わるんじゃないの。
断言はできないけどね。

評価

0

いつもご指導ありがとうございます。

addのみでremoveしていません。
早速試してみます。

以下を繰り返し

imagex=ImageIO.read(bais);//bais==>ByteArrayInputStraem
ImageDraw ih =new ImageDraw();
bais.close();//bytearrayinputstream

frame.remove(0);
frame.validate();
frame.add(ih,BorderLayout.CENTER);
frame.setVisible(true);

評価

0

sleepしてるんだろうか。

評価

0

いつもご指導ありがとうございます。

上記、addとremove()を繰り返し、-Xms12m -Xmx12m でメモリー割当量を少なく設定しましたが、短時間で同じようになるようです。

エラーは、以下のとおりです。

Exception in thread-0" java.lang.OutOfMemoryError: Java heap space
  at java.awt.image.DataBuffereByte.<>(Unknown Source)
  at Java.image.ComponentSampleModel.createDataBuffer(Unknown Source)
  at java.awt.image.Raster.createWritableRaster(Unknown Source)
  at java.imageio.ImageTypeSpecifier.createBufferedImage(Unknown Source)
  at java.imageio.ImageReader.getDestination.readInternal(Unknown Source)
  at java.imageio.plugins.jpeg.JPEGImageReadInternal(Unknown Source)
  at java.imageio.plugins.jpeg.JPEGImageReader.read(Unknown Source)
  at javax.imageio.ImageIO.read(Unknown Source)
  at javax.imageio.ImageIO.read(Unknown Source)
  at ImageGet.run(Test33.java:534)

以上よろしくお願いします。


  

評価

0

付け加えますと、12mで割り当てて実行したところ、ヒープメモリーの使用状況(jconsole)は、はじめは5-10Mで大きく振れていたのが、上限は12のままで段々と振れ幅が時間とともに小さくなり、最後は殆ど振れ幅がなく、12mで上限のまま停止状態となり、上記エラーが発生します。

よろしくお願いいたします。

評価

0

そういうツールは、使い方を理解して初めて意味のあるものだ。
今の君がやっていることには、なんの意味もない。

評価

0

とりあえず画像1枚だけでやってみたらどお?
次は2枚
次は3枚
どこでパンクするか1つずつ確かめるべきよ。

評価

0

万を超えるような画像が相手じゃ、
それはさすがに厳しいのでわ。w

まずは、frame.getComponents()で、どんな数字が出るのか確認してみては。
それにしても、JFrameに直接addしちゃっていいもんなの?
ちゃんとgetContentPane()を使いなさいよ。

評価

0

それと。
remove()を追加したようだけど、
これで本当に、目当ての画像を削除できてるの?

評価

0

色々ご指導ありがとうございます。

ひとつづつチェックしていきます。

評価

0

つか、いくらremove()しても参照がなくなり、ガベージコレクションが走らなければメモリは解放されないが…。

評価

0

100個200個ってやっていけばいいじゃない。
別に216枚と勘違いしたわけじゃないんだからっ。
どきどき

評価

0

俺なら、removet対象格納用変数をひとつ、
新規画像格納用変数ひとつで、処理するな。
これなら参照を保持している箇所を2箇所に絞れる。
この2変数をどんどん上書きしてきゃいいじゃん。
GCは、適当に走ってくれるでしょ。

>てんこ氏
いやあ、俺だったらこの場合、getComponents()の
返り値が1より多かった時点でダメ出ししちゃうから。

評価

0

あう、getComponents()じゃなくて、
getComponentCount()の方だった。orz

評価

0

てんこ様

私の文章が下手なのか、もし解釈を間違っていたらすみません。
remove()なしで、frameに直接画像を描画し、6時間程度は、秒10コマ程度で動画のように表示しております。
そのあと、急に表示が遅くなり、オーバーフローします。
そのため画像216,000枚程度まで表示しました。-Xmx126m

1枚だけの画像表示は問題ありません。
また、2,3と増やしても大丈夫です。(再チェック済み)


不良社員様

まずは、ループに下記挿入で、
System.out.println(frame.getComponentCount());→@1037c71とかでばらばらです。(?調査要)
System.out.println(frame.getComponentCount());→必ず1になるのでフレームは1つではないのでしょうか?
getContentPane()を調べてみます。
前にも気になったのが、万を超える画像が相手だと・・・という一節ですが、インスタンスがどんどん作り続けるとメモリーが消費されて、最終オーバーフローになるということでしょうか?
そうするとインスタンスが増加するような永遠と続くプログラムは作れないのでしょうか?
低レベルで申し訳ございません。
ご教示ください。

評価

0

いつもありがとうございます。
↑上を書いてる最中にたくさんご回答ありがとうございます。

話が前後してるかもしれません。

評価

0

>そうするとインスタンスが増加するような永遠と続くプログラムは作れない
そりゃそうだ。
インスタンスは、突き詰めればメモリの固まり(サイズは大小様々だが)をそう呼んでるに過ぎない。
メモリが無限にあるなら、インスタンスも無限に作れる。

なんか考え違いをしてるようなんだが…。
1枚の画像を表示するとき、本当にその前のフレーム(コマのほうの)で表示していた画像は必要なのか?その前の前のフレームの画像は?
トータルで何枚必要かじゃなくて、いちどきに何枚必要かを考えてみる。

評価

0

>ばらばらです。(?調査要)

getComponentCount()の返り値はintのはずだがな。

>フレームは1つではないのでしょうか?

本当に、「画像をaddしてるComponent」のgetComponentCount()の値なのか?

きちんと理解してオブジェクトを識別しないと、
GUIはうまくは扱えないよ。

>インスタンスが増加するような永遠と続くプログラムは作れないのでしょうか?

逆に聞くけど、どんどん増えるインスタンスを、
どこにどうやって格納するってのさ。

ところで、いったいどうしたいの?
こんなやり方で、なん10時間分もの画像を
抱え込めるようなプログラムにするつもり?

評価

0

いつもありがとうございます。

>トータルで何枚必要かじゃなくて、いちどきに何枚必要かを考えてみる。

私も、主眼は、1つの変数imagex(画像を格納場所)だけで前後の画像関係なく、上書きして処理していると思っています。
そうしないといくらメモリーがあっても無理なのは理解しています。
例えば、下記を何度も実行しても、imagex,bais,ihの変数自体が1つなのでメモリーは各々1つと考えておりますが・・・。
(今回、画像の表示追加で増えた問題になるインスタンス)
imagex=new BufferedImage(640,480,BufferedImage.TYPE_INT_RGB);
ByteArrayInputStream bais = new ByteArrayInputStream(bybuff);
ImageDraw ih =new ImageDraw();

何度もすみません。よろしくお願いいたします。

評価

0

for (int i = 0; i < 3; i++) String s = Integer.toSring(i);
sのインスタンスはいくつできる?

評価

0

いつもありがとうございます。

3つです。
確かに、1つが3つに増えました。
まず、チェックしてみます。

評価

0

俺ならこうかなあ。

ArrayList<Integer> array = new ArrayList<Integer>();
for ( int i = 0; i < 10; i++ ) {
  Integer hoge = new Integer( i );
  array.add( hoge );
}

hogeは使ってすぐ捨てているんだから、ループ脱出後は、
Integerのインスタンスは、ひとつも生存していない。
yes or no ?

評価

0

すみません。
早とちりです。
いつもの私ですと、sは1つで、3回入れ替わって、最後の3番目のsが一つだけです。

試してみます。

評価

0

いつもありがとうございます。

不良社員様

理解できない内容で実験しないとわかりません。
おそらく最後に1つ・・・。

うーーーん。
ここまで来ますと、どうも20万枚メモリーに貯めているおバカなプログラムを作っていたぽいですが・・・・。

評価

0

>俺ならこうかなあ。
うん、それが次の段階だな。

まずは変数の数とインスタンスの数がイコールとは限らないことを言い、次に格納していた変数のスコープが終わっても、無条件にインスタンスが消えるわけではないことを言いたかった。

>20万枚メモリーに貯めているおバカなプログラムを作っていた
そう、みんなそう思ってる。
だから、使う必要がなくなった1枚のメモリが開放されそうなremove()が、案として上がった。
でもそれでは変わらなかったというのだから、さらに別の問題があるだろう。

評価

0

>別の問題があるだろう。

remove()の問題も、まだ解決してないと思う。
さらに、indexを指定するより、削除対象のオブジェクトそのものを
指定した方が確実だろう。

そもそも、対象のComponentが正しいかどうかまだわかんないし。
これがその次の課題かな。

評価

0

いつもありがとうございます。

難問は調べてみます。
まずは、ここまではつぶしておきます。

remove()がわかりにくく、dispose()でいくと画面が消えてわかりやすいのですが、これでも同じ気配(調べきれていませんが少しやってると)がしました。まだつかみきれないjconsoleですが・・・。

途中記載して前から気になってたのですが、メインのImageGetクラスは、Threadクラスを継承して、何か所からでも画像をゲットできるよう拡張しできるよう欲張りました。
SWINGがシングルスレッドで、イベントディスパッチスレッド・・・・とか何とかが引っかかるようなきがしますが、これ自体は関係ないでしょうか?


ソース構成
 ImageGetクラスでほとんどの仕事をしています。
 実行はTest33.java

class ImageGet extends Thread {//
   ・
   ・
  class ImageDraw extends JPanel{
   ・
   ・   
  }//class ImageDraw

}//class ImageGet
   ・
class Test33 {
    public static void main(String args[]) {//main
       ImegeGet get1 = new Recorder(0);
          get1.start();
  }//main
}//class Test33

以上よろしくお願いいたします。

評価

0

一度に考えることは、ひとつだけにしたまえ。

評価

0

いつもありがとうございます。

>ArrayList<Integer> array = new ArrayList<Integer>();
>for ( int i = 0; i < 10; i++ ) {
>  Integer hoge = new Integer( i );
>  array.add( hoge );
>}

意図するところよくわかりました。
調べたところ、hogeは、1つですが、配列1つ1つに0-9までの数字が各々入っている。
よって、単純に解釈しても10個分メモリーを使っている。

同じように、画像も20万枚入ってないか・・・・。
了解しました。(深いです・・・)
チェックしてみます。

評価

0

arrayに追加しないでも、ループを抜けるまでは多分10個分消費してる。

繰り返しになるが、変数が占有するメモリが解放されるタイミングは、変数が使われなくなったときじゃない。
ガベージコレクションが発生し、かつその変数が使われていないと判断されたときだ。

評価

0

ん? 肝心の点は、そこじゃないんでわ。

arrayに格納されたIntegerのインスタンスは、
ループを抜けたあとも、arrayが保持される間は、
ずーーーーーっと存続するんだぞ。

20万枚の画像が、addしたComponentで、
ずーーーーーっと保持されるのは、
基本的に、これと同じ理屈だ。

評価

0

今回の原因がこれだと言ってるわけじゃない。
根本を把握しておけってこと。
remove()すればメモリの使用量を一定にできると思われないように。

評価

0

じゃ、さっきの投稿は断言になっちゃうかな。
俺はそういう線で考えてるって事にして。

評価

0

いつもご指導ありがとうございます。

現状、恐らく配列で画像をたくさんも持っているようなプログラムの内容になっていないと思います。
上記、ご指南いただきました配列bybuffはそのままImageIOのストリームとして使用しています。(2009/03/18本掲示板  ※これを書き忘れてました)
たくさんの画像が配列としてあるところで、ImageIOに繋ぐストリームする・・・・今の私では難しいです。

ひょっとしたら、50kbyte画像を秒10コマで1時間メモリーに保持するとなりますと、1.8GByteくらい必要になる???

もう一度ゆっくり読みなおしてみます。

評価

0

ご無沙汰しております。
問題が解決しました。皆様のおかげです。

結局、配列の問題はなく、ご指摘ありましたとおり、トップレベルコンテナのJFrameに直接画像を貼り付けてaddすることは可能でしたが、限界があることがわかりました。

中間コンテナに画像を貼り付けて、remove()して、必ず画像を1枚だけにすると問題なく動作しています。
次のステップに挑戦してみます。

本当にありがとうございました。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。