Tips : Processing PImageのメモリリーク対策
ProcessingのPImageには、メモリリークの問題があるので、その回避方法を書きとめておきます。ちなみに、僕の環境ではProcessing 2.1を利用しています。
通常loadImage()
などでsetup()
内から1度呼ぶくらいであればリークすることはないと思いますが、
draw()
の中でcreateImage()
などを実行しているようなケースでは、PImageを作るたびにメモリが確保され続け、いずれExceptionしてしまいます。
僕が書いていたコードを例に、回避の仕方をまとめます。
カメラキャプチャイメージを集めて利用するケーススタディ
例えばカメラからの動画をずっと貼り付けておくのではなく、特定フレーム毎に静止画としてカメラキャプチャ画像を取得して、画像としてを利用するケースを考えます。
少し省略しますが、下記のように毎秒1フレームでキャプチャを取得してArrayListにスタックすることを考えます。
import processing.video.*; Capture cam; ArrayList<PImage> imgs; void setup(){ frameRate(1); String[] cams = Capture.list(); if(cams.length == 0) { exit(); } else { cam = new Capture(this,cams[0]); cam.start(); } imgs = new ArrayList<PImage>(); } void draw(){ if (cam.available() == true) { cam.read(); } PImage tmp = cam.get(); imgs.add(tmp); }
この例だと、実行して放置するとExceptionしてしまいます。
これを回避する方法はGithubのIssueのスレッドにあるのですが、
g.removeCache(image)
を追記するのが有効です。
void draw(){ if (cam.available() == true) { cam.read(); } PImage tmp = cam.get(); imgs.add(tmp); g.removeCache(tmp); }
さらに、ArrayListを空にするタイミングでも、実行する必要があります。
void draw(){ if (cam.available() == true) { cam.read(); } if (imgs.size() > 10) { for (int n = 0; n < imgs.size(); n++) { g.removeCache(imgs.get(n)); } imgs.clear(); System.gc(); println("cleared buffer size: "+ imgs.size()); } PImage tmp = cam.get(); imgs.add(tmp); g.removeCache(tmp); }
System.gc()
も加えていますが、これだけだと回避できませんでした。
なのでArrayListに入っているPImageの参照ひとつひとつにremoveCache
をする必要があります。