« Android での起動時間 | メイン | InterCodeContext を分離 »

2012年01月03日

吉里吉里Java:: OutOfMemory対策

    

Android で画像を読み込んだり、生成した時によく発生する OutOfMemoryError 。
本当にメモリが足りない時はどうしようもないが、解放されずに残っているオブジェクト等の影響で確保に失敗することがある。
このような状況を避けるためには、単純に以下のようにして1度目は OutOfMemoryError 例外をキャッチして、GC を実行し、再度確保を試みるようにすれば、成功することが多い。
当然、自身で多くのメモリを使用している場合はどうしようもない。

try {
 mImage = Bitmap.createBitmap( w, h, Bitmap.Config.ARGB_8888 );
} catch( OutOfMemoryError e ) {
 java.lang.System.gc();
 // 2回目は try-catch せず、2回目も失敗した時は諦める
 mImage = Bitmap.createBitmap( w, h, Bitmap.Config.ARGB_8888 );
}

後、Bitmap は不要になった時、bitmap.recycle(); して、null を代入しておいた方が良い。
recycle() は、ネイティブオブジェクト(ピクセルデータ) との関連を強制的に断ち切る。
Bitmap オブジェクトが他で参照されていても GC が発生したら、ピクセルデータは解放される。
当然、再使用しようとしたらエラーになる ( isRecycled で使えなくなっているかどうか確認できる )。

吉里吉里Java だと、上記の GC を試してみる前に、System.doCompact 処理を実行して、内部のキャッシュを参照解除 して、GC で解放されるようにする。
これで出来るだけメモリを空けて Bitmap の読み込みや生成が成功するようにする。
このような処理で OutOfMemoryError で落ちる確率は減るが、GC が走ると数百msec程度処理が止まる。
落ちるよりはマシだが、カクつく原因にはなる。

再読込等で生成しやすい画像データは、読み込んだ後 recycle() をあらかじめ実行して置いて、必要時にはisRecycled でまだ使えるかチェックして、使えなくなっている時は再度読み込んで必要な処理を行うことで、より OutOfMemoryError に陥る可能性を減らせるようだが、頻繁に再読み込みが発生すると困るので、このような処理は行っていない。
メモリ的に厳しいようであれば、このような処理も検討する。
実際問題として recycle() した後どの程度解放されてしまうのかによっては、普通に使用しても問題ないかも知れないが、ドキュメントを見る限り次に GC が実行されたら消えてしまうように思える。
2回目もメモリ確保に失敗した時は、ロードしやすいデータは recycle() してしまい、OutOfMemoryError で落ちる確率をより減らすような処理があった方がいいかもしれない。
ただ、その場合は今表示されているデータが解放されてしまい、ロード地獄に陥るかも知れないが。



投稿者 Takenori : 2012年01月03日 22:05




comments powered by Disqus
Total : Today : Yesterday : なかのひと