今作ってるアプリのアイテムもやっと150個全部入力し終わり(なぜか作ってる途中で10個ほど増えた)、他の部分の調整もしてデバッグしてると、また噂のOutOfMemoryErrorがでるようになった。
それで今まであれこれ調節してやっと1時間近くプレイしても発生しなくできたし、これを機に自分の為にもやったOutOfMemoryError対策をまとめとこっかなって思います。
(ただあくまでぼくのやり方で、これでいいのかどうかはよくわかりません・・・)
その1.メモリリークを起こさない
基本中の基本らしいです。できてるか不安だけど。
javaってGCという仕組みがあるからあんまりメモリのことは気にしないでいいというようなことが書かれてるけど、少なくともAndroid開発に限れば嘘っぱち。
Androidでメモリリークする主な原因は下記URLのを参考にしました。
Androidのソースコードレビュー(メモリリーク)-暇なメモ帳
あと、Javaはガベージコレクション(GC)でメモリの解放をするらしいけど、そのGCで解放される最低条件が「どこにも参照されてない」ことみたい。
だから参照を切ったら(きっと)GCは食べにきてくれる。
※食べるという言い方は多分ぼくしかしません。便宜的にそうイメージしてるので。
「まあ要は毎回使い終わったら参照を切っとけば安心なんでしょ」ってことで、
作った全てのClassに以下のインターフェイスを実装し、ActivityのonDestory時に全部実行されるようにした。
public interface Disposable{ public void dispose(); }
protected void onDestroy(){ //ここにActivityで参照したものをdispose()する。 view.dispose(); view = null; }
このviewの中でも参照したものは全部dispose()し、その参照先でもdispose()していく感じで全部に走らせた。
ただ同じインスタンスを複数のインスタンスで参照する場合、再びdispose()するとぬるぽが発生することもあるんで、それを管理するクラスを作って一度きりしか呼び出されないようにした。
多分これでメモリリークはおきない(はず…きっと…自信ないけど…)。
その2.何度も呼び出す巨大画像はSingletonクラスに入れてキャッシュしとく。
これが一番対策として間違えてないか自信ないけど(Androidではsingletonは使わない方がいいという記事も沢山あったし)、何度も何度もBitmapFactory.decodeResource()で読み込むのはヤだったから、巨大でかつ何度も呼び出すものはSingletonパターンのクラスを用意してそこにいれとくことにした。
そのクラスがGCに食べられちゃってる場合は(多分)その画像データも食べられてるし、その時はまた読み込めばいいやと思って。
//たとえばの例 public class SingletonData{ private static SingletonData singleton = new SingletonData(); private Bitmap bmp = null; public static SingletonData getInstance(Resources $resources){ singleton.init($resources); return singleton; } private void init(Resources $resources){ if(bmp == null){ bmp = BitmapFactory.decodeResource($resources , R.drawable.img); } } public Bitmap getBitmap(){ return bmp; } }
心なしか、そうやってからはかなり安定するようになった気がする。
その3.Bitmapの読み込み時の階調を調節する。
ここのを参考にしました。
AndroidでBitmapを操作する際のOutOfMemory対策
特にアルファ値が必要ない場合はRGB_565で、そんなに淡い色を使ってない場合はARGB_4444で読み込むようにすると、かなり安定するようになりました。
その4. onDestory時にSystem.GC()を走らせる
邪道な気がしなくもないけど、全部参照を切ったあとGCパックンに走ってもらうと無双してくれてる気がする。
あとはBitmapは使い終わったらrecycle()をするとか、不必要にインスタンス量産しないとかそんな感じで調整していくと無事おこらなくなってくれました。
今のところは。
ただ、しつこいけど、これでいいのかどうかよくわからない(´・ω・`)
間違えてたりこうする方がいいよとかあったら指摘してもらえるとうれしいです。