2011年10月25日火曜日

Bitmap(特に写真)を表示するアクティビティでOutOfMemoryError

Androidのアプリケーション開発ではまった罠の第二弾。


おそらく、カメラで撮影した写真を表示するアプリケーションを開発したことがある方であれば、「あるある」と思っていただけるのではないかと。


機種にもよりますが、Android携帯で撮影した写真は、jpeg画像であっても数MB程度のサイズであることがあります。


PCで数MB程度の画像を表示することは、大したことではないのですが、Android携帯では問題になることがあります。


これまた機種にもよりますが、開発者が使えるメモリ空間がメガバイト単位でしか存在しないわけですし、そのメモリ空間は自分が開発するアプリ以外も利用するわけです。


そんな状況で、撮影した写真をサイズを小さくすることなく、何枚も読み込んだら何が起きるかはお分かりかと思います。メモリ不足です。


「何枚も読み込んだら」と言いましたが、これには「同じ画像を何度もファイルから読み込んだら」も含まれる場合があります。


実際に経験したケースが、次のようなものです。


撮影した写真をイメージビューに表示するアクティビティAがあるとします。このアクティビティAには、別のアクティビティBから遷移してきます。


アクティビティAを作成し、単体テストをしているとき、たまたま操作を誤ってB→A→B→Aという遷移を2、3回繰り返したところ、EclipseのLogcat上に「OutOfMemoryError」が出力されました。


原因は明らかです。アクティビティAで大きな画像を読み込むことで、メモリが不足したのです。もちろん、AからBへ遷移するときには、写真(Bitmapオブジェクト)への参照はすべて廃棄していました。が、それでもOutOfMemoryError。


当たり前のことですが、参照を破棄したからといって即GCが自動実行されるわけではありません。このケースでは、画像を読み込む→参照をすべて破棄→画像を読み込む→参照をすべて破棄がGCが発生する前に繰り返されたため、メモリ不足になったことが原因でした。


解決法は簡単。GCを明示的に実行すれば良いだけのことです。


画像の読み込みと破棄、GCについてはこちらの記事が良質ですので、Bitmapを扱うアプリケーションを作る前に一度は読んでおくことをオススメします。


http://groups.google.com/group/android-group-japan/browse_thread/thread/fa40fe4d250541f5?pli=1


まとめ:資源は有限!