Kasasagi’s memorandum

JavaとかProcessingとか。最近はAtcoderとか。

OutOfMemoryErrorに苦しんだ話

こんばんは。自分のやってることはわざわざblogじゃなくてQiitaですればよかったんじゃね、って思い始めたかささぎです。

 

IntellijJavaのとあるプログラムを書いていたらこんなエラーが出てきました。

java.lang.OutOfMemoryError: Java heap space

 at うんたらかんたら...

 

ヒープ領域というのは、メモリ内でスタックのように積み上げていく感じのとこですね。前の記事(拝啓 Processingを馬鹿にする輩へ - Kasasagi’s memorandum)で書いてたprocessingをJavaで書いてるプログラムで、loadImage()関数を呼び出した際に発生しました。メモリが足りないなら増やすしかないじゃないという脳筋発想で、まずはideaのJVMのメモリサイズを増やすことにしました。

やり方

Help > Edit Custom VM Option...を選択。

ファイル作るで、みたいなダイアログが出るのでOKを押すと、idea64.exe.vmoptionsというファイルが開かれます。これを書き換えました。

f:id:yh9092:20171112205805p:plain

Xms、Xmxを1024m(メガバイト)にしました。Xmsはヒープ領域の最小容量、Xmlは最大容量みたいです。同じにするのはあまりよくないのかもしれませんが、まあ分かんないんで一緒にしました。変更後は再起動させて反映されます。ちなみに2048mにしたら、PCが寿命を削るような音を出し始めたので、戻しました。

 

これを行ったのですが、解決しませんでした。画像ファイルの容量を眺めながら、ヒープ領域が足りなくなるわけなくね?とか呟いてる際に、以下のHPを見つけました。

loadimage, big images and memory... - Processing Forum

Processingのteratailみたいな感じですね。ほとんど英語なので、英弱にはつらみ。

この質問の解答過程にこんな内容があります。

f:id:yh9092:20171112210837p:plain

要約すると、

「PGraphicsで8628*12545の画像生成したら、440MBのRAM使ったで」

「loadImageしたらさらに950Mb使用したわ。Processingが悪いんかJavaが悪いんかわかんね。」

って感じです、たぶん。つまり何が言いたいのかというと、loadImageする際には、画像のデータ容量だけでなく、もっと多くの"なにか"が加わるみたいです。おそらくそいつのせいでヒープが死んでたみたいです。

自分のプログラムでは4000*6000pxで1MBぐらいの大きな画像ファイルをloadImage()していました。ただ、テスト用に入れておいた400*600pxで10KBぐらいの小さな画像ファイルなら、正常に読み取ることができ、表示もできました。そこで、どのくらいの大きさまでなら動くかを検証することにしました。

検証していくうちに気付いたのですが、使用されるRAMの量は、画像ファイルの容量でなく、ピクセル数に相関性があることがわかりました。PImageはBufferedImageか何かに変換されているんですかね?

よくわかんないですが、2000*3000pxの画像はちゃんと読み取れることが確認できました。プログラムではB5用紙をスキャナで読み取った画像を利用するのですが、2番目に高い解像度の設定だとそれぐらいになります。課題とはいえ、提出のためだけのプログラムにしたくなかったので本当に良かった。。。

 

また、何かに躓いてそれを解決したら書くかも。

それでは。