2012年5月19日土曜日

【Android】BitmapによるOut of Memoryについて

今回はBitmapが原因で起きるOut of Memory Errorについて書きたいと思います。
これは筆者が作ったアプリがOS2.3まではサクサク動いていたのに4.0のGalaxy Nexusを使用した際にロードが極端に遅くなりOut of Memory Errorで落ちる現象が起き、色々調べた結果わかったことを書きます。

もちろんBitmapをロードしたりしたらちゃんとbitmap.recycle();を使ったほうがいいですし、その直後に強制的にSystem.gc();を使って強制的にGarbage Collectionを呼んだらいいとよく書かれています。それらをやっても落ちることがあります。

Androidのリソースフォルダの中には色々なdrawableで始まるフォルダがあります。
デフォルトはdrawableですが、プロジェクトを新たに作るときは(対応OSバージョンにもよりますが)drawable-ldpi, drawable-mdpi, drawable-hdpi, drawable-xhdpiとあります。

これらは端末の解像度(正確には画面の密度)によって選択するリソースを変えるためにあります。本来の使い方であればそれぞれのフォルダに違うサイズに切り分けた同じ名前の画像ファイルを入れます。ただし、ファイルが大きくなってしまうので画像を1枚だけ用意してデフォルトのdrawableやmdpiのフォルダに入れる人も多いかと思います。筆者もそうでした。

Androidのシステムはまずリソースから画像を取って来いといわれたら端末の解像度に一番あったフォルダから探します。内場合は徐々に下っていき、最終的にはデフォルトのフォルダから引っ張ってきます。もし端末の解像度に合ったフォルダから取ってきた場合はその画像を拡大・縮小してロードします。

もしdrawable-mdpiのフォルダに画像を入れていて端末がxhdpiの端末の場合画像をかなり拡大してロードされます。特に大きな画像(背景など)はかなりのダメージを受けます。
そして筆者のミスはdrawableフォルダに画像を入れていたことでした。drawableのフォルダは実はdrawable-mdpiと同じ扱いを受けるのです。

例えば720x1280の背景画像を使うとしましょう。これをdrawable, drawable-mdpiなどのフォルダに入れるとxhdpiやhdpiの端末では拡大してロードされます。hdpiでは約1.5倍、xhdpiでは約2倍のサイズでロードされます。

なので、画像はそれぞれのサイズに合ったフォルダに入れましょう。720x1280の画像をxhdpiのフォルダに入れればxhdpiの端末ではそのままロードされます。そしてmdpiの端末では縮小してロードされます。

ただし、あまりにも拡大・縮小率が高くなるとやはり画像は荒くなります。
そこで、drawable-nodpiというフォルダをつくり、画像を入れると、どの端末でも画像そのままのサイズで使ってくれます。ただし、なんでもかんでも全部これに入れると、メモリの少ない端末などではOOMを起こしてしまうようになるので気をつけましょう。また逆に拡大・縮小してくれるとありがたい素材などもあります(ボタンなど)。

なので、なるべく画像はその画像のサイズに適したフォルダにいれるようにしましょう!また画像を用意するときにサイズをよく考えて作りましょう。
もし1サイズしか用意できないのであれば恐らくhdpi辺りのサイズの画像がいいでしょう。2サイズ用意できるのであれば大きめと小さめなどを用意しておくといいかもしれません。

とにかく大事なのは、Androidではシステムが自動でリソース画像を拡大・縮小するという事を知っておくことです。Androidは色々な解像度の端末があり、それに対応するための便利なシステムではありますが、同時にちゃんと理解していないとメモリの無駄遣いやOOMエラーに繋がります。

ちなみに筆者のアプリは90%~98%のメモリusageだったところが画像をフォルダ移動しただけで50%台まで落ちました。(これは3.0以降の端末となります。3.0まではBitmapはDalvik heapではなくnative heapに保存されていたのでDDMSのheap dumpでは見れませんでした。見る方法はありますが・・・)

というわけでOOMエラーに悩まされている方は一度リソースを置いているフォルダをもう一度確認してみてください!

英文ですが、詳しくは下のAndroid Developersのサイトに詳しく書かれています。
http://developer.android.com/guide/practices/screens_support.html

0 件のコメント:

コメントを投稿