ヒープサイズ

OpenCVを利用したサンプルアプリケーションをandroidプラットホームに移植しているのだが、Bitmap生成に起因するOOM(Out of Memory)に悩まされている。

以前にエントリに書いたように、ハードウェアアクセラレーションを有効にした状態で扱える最も大きな画像データのサイズは2048x2048だが、この位のサイズの32bitColor画像(約6MBある)を扱おうとすると、2値化 -> 輪郭抽出辺りでOOMに遭遇できる。

アプリケーションとビューでは内部でBitmapクラスを使用しているので、最初はメモリリーク(BitmapはネィティブヒープにアロケートされるためGC下でもメモリリークとなる)かと思い、処理を見直した。

Bitmapクラスの最適化
  • 不要になったBitmapのrecycleを実施
  • 同様にsetDrawableメソッドを使った場合にnullクリア
  • 動的な多重生成を抑制するためにLruCacheを導入 (※これはかなり効いた)

しかしこの状態でもOOMが発生するのである。

GCログを見るとアプリケーションを初期化して一度目の実行を行った時点でヒープが51.267MBであり、通常のandroidのアプリケーションヒープの上限である64MBまで既に残り15MBを切っている。

: I/jp.xxxxxx.MainActivity(1579): OpenCV loaded successfully
: W/EGL_emulation(1579): eglSurfaceAttrib not implemented
: I/dalvikvm-heap(1579): Grow heap (frag case) to 51.138MB for 14962300-byte allocation
: I/dalvikvm-heap(1579): Grow heap (frag case) to 51.322MB for 14962300-byte allocation
: I/dalvikvm-heap(1579): Grow heap (frag case) to 51.267MB for 12369932-byte allocation
---------------------------------------------- ここまで 2値化 → 輪郭抽出 ------------------------------------------------------

そして、もう一度処理を頭から繰り返そうとすると、OOMだ。

: I/dalvikvm-heap(1579): Forcing collection of SoftReferences for 14962300-byte allocation
: E/dalvikvm-heap(1579): Out of memory on a 14962300-byte allocation.
: I/dalvikvm(1579): "main" prio=5 tid=1 RUNNABLE
: I/dalvikvm(1579):   | group="main" sCount=0 dsCount=0 obj=0xb2fdf4b0 self=0xb97e74e0
: I/dalvikvm(1579):   | sysTid=1579 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1206942656
: I/dalvikvm(1579):   | schedstat=( 0 0 0 ) utm=76 stm=7 core=0
: I/dalvikvm(1579):   at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
: I/dalvikvm(1579):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:500)
: I/dalvikvm(1579):   at jp.xxxxxx.MainActivity.createBitMap(MainActivity.java:193)
: I/dalvikvm(1579):   at jp.xxxxxx.MainActivity.doFindContour(MainActivity.java:160)
: I/dalvikvm(1579):   at jp.xxxxxx.MainActivity.onOptionsItemSelected(MainActivity.java:137)

ログからはヒープの伸びも頭打ちもまだはっきりしないため、まだメモリリークがあるかどうか分からない。
もう少し大きなヒープで試したい所だ。

Displaying Bitmaps Efficiently | Android Developers