Bitmap を SoftReference で管理すべきではない
追記:3.0 より Bitmap はネイティブヒープを利用しなくなりました。キャッシュは 3.1 以降なら LruCache を使えば大体問題ないと思います。
手が痛いので、簡単に。
一年以上前の記事ですが、CacheオブジェクトにはSoftReferenceをとか、最近だと、WeakHashMap なるものがあるのねなどのページで、Bitmap を SoftReference で管理しよう!みたいなのが紹介されていますが、
それなりにヒープを消耗する場合は Bitmap の開放を GC に任せてはいけません。
そんなわけですから、面倒ですが recycle メソッドをちゃんと呼んであげましょう。ドキュメントに "normally need not be called" とありますが、これは「ヒープによほど余裕があるなら呼ぶ必要はない」と読み替えてください。実際そうです。
そもそも Bitmap とは、ネイティブヒープ上に確保されたバッファを保持するクラスなわけですが、このバッファは GC が直接管理しているわけではありません。GC が管理しているのは、あくまで Bitmap オブジェクトです。GC さんが頑張ってお掃除しても、ファイナライザが呼ばれるまでは、ネイティブヒープに余裕はできません。これは、ネイティブヒープが逼迫し GC が行われても、すぐにはネイティブヒープは回復しない、ということを意味しています。割合残念な事実ですね。
SoftReference を使うと、問題は更に深刻化します。GC に回収されるタイミングが、通常の strong reference よりも遅くなってしまいます。勿論そのために SoftReference は存在するわけですが、GC に回収されるタイミングが遅くなれば、当然ファイナライザが呼び出されるタイミングも遅くなります。結局のところ、手遅れ(OutOfMemory)になりやすくなります。*1
どうしても SoftReference によるキャッシュ機構を利用したいなら、SoftReference で直接 Bitmap を管理するのではなく、Bitmap の所有権をあらわすオブジェクトを SoftReference で管理し、更にそのオブジェクトが ReferenceQueue に積まれるのを監視し、積まれたタイミングですぐに recycle メソッドを呼んでやるようにしましょう。こうすれば、手遅れになる可能性は比較的低くなります。勿論、手遅れになってしまうこともあります。SoftReference 周りの実装をよく分かった上でなら、意味があるかもしれません。そうでないなら、苦労の割りにあまり効果がなくても、文句は言えませんね。はい、言いません…
…それでも、OutOfMemory もちゃんとリカバーして待っていれば、いつかはネイティブヒープに余裕ができるのではないか、皆さんはきっとそうお考えでしょう。
甘い…ッ!甘すぎる……ッ!!
____________ ヾミ || || || || || || || ,l,,l,,l 川〃彡| V~~''-山┴''''""~ ヾニニ彡| finalize する・・・・・・! / 二ー—''二 ヾニニ┤ finalize するが・・・ <'-.,  ̄ ̄ _,,,..-‐、 〉ニニ| その時の /"''-ニ,‐l l`__ニ-‐'''""` /ニ二| 指定まではしていない | ===、! `=====、 l =lべ=| . | `ー゚‐'/ `ー‐゚—' l.=lへ|~| そのことを |`ー‐/ `ー—— H<,〉|=| どうか諸君らも | / 、 l|__ノー| 思い出していただきたい . | /`ー ~ ′ \ .|ヾ.ニ|ヽ |l 下王l王l王l王lヲ| | ヾ_,| \ つまり・・・・ . | ≡ | `l \__ 我々がその気になれば !、 _,,..-'′ /l | ~''' finalize は ‐''" ̄| `iー-..,,,_,,,,,....-‐'''" / | | 10年後 20年後ということも -—| |\ / | | 可能だろう・・・・・・・・・・ということ・・・・! | | \ / | |
はい、皆さんの甘い考えはぶち殺されました。よかったですね!ちなみにこれ、冗談とかではなくて、Dalvik が何やってるのかは知りませんが、ファイナライザスレッドがいつまでたっても仕事しないことは、実際ありました(ドヒャー)。そうなったら、もう参照は失われていますから、どうしようもありません。おしまいです。そうならないためにも、明示的に recycle メソッドを呼び出してやる必用があるのです。
そもそも finalizable なオブジェクトと SoftReference の相性は、あまりよくないと思います。これはボクがそう思っているだけで、一般的にどうなのかはちょっとよく分からないです。実際そうなんじゃないかと思っているんですが、java の GC 事情に詳しい方教えてください…あと android というか Dalvik のその辺の事情に詳しい方も色々教えてください…
うあー全然簡単になりませんでした…おしまい。