Android

【Android】OutOfMemoryと戦う【OOM】

More than 3 years have passed since last update.


\ OutOfMemoryが出たぞー! /

どうする?

1.  画像の息の根を止める

2.  メンバー変数は全て息の根を止める

3.  それでもダメならLargeHeap

基本的には1と2までで大丈夫だと思います。

LargeHeapまで行く場合は、絶対的に画像などの読み込み量が多い時ぐらいにした方が良いと思います。


1. 画像の息の根を止める


  • Bitmapを使う場合


Bitmap bitmap;

private void releaseBitmap() {
if (bitmap != null) {
bitmap.recycle();
bitmap = null;
}
}


  • ImageView(ImageButton含む)を扱う場合


ImageView imageView;

private void releaseImageView(){
if(imageView != null){
// src に画像を設定した場合はこっち
imageView.setImageDrawable(null);
// background に画像を設定した場合はこっち
imageView.setBackgroundDrawable(null);
}
}

ImageButtonも同様にやっておきましょう。

忘れがちな事は、backgroundに設定している画像をsetImageDrawable(null) では潰せないことです。

どうせ解放するので、常に両方やっちゃっても構わないと思います。

(ちなみに、Fragment の場合、タイミングは onDetach() でやることをオススメします。以前、onViewDestroyed() でやったら、popBackStack 時のアニメーション前に解放されておかしな挙動になりました。)


2. メンバー変数は全て息の根を止める

それでも何か漏れていたら、とにかくreleaseしてnullで潰していきましょう。

classによって解放の仕方は異なるので、乱暴にnull埋めするだけだとNGの場合があるので気をつけて下さい。

例えば ListView の場合は

    ListView listView;

ArrayAdapter<String> arrayAdapter;

private void releaseView() {
if (listView != null) {
listView.setAdapter(null);
listView = null;
}

if (arrayAdapter != null) {
arrayAdapter.clear();
arrayAdapter = null;
}
}

こんな感じ。

画像を使ったListViewとかだと、漏れるとシャレにならない場合があります。


3.それでもダメならLargeHeap

4系以降のみです(kacchan6@githubさん、ご指摘ありがとうございます。)

どうしても画像が多くて、setContentView()でlayout読み込む時点でOutOfMemory を吐いてしまう様なレベルの場合は、これでヒープの使用量を増やしてしまうのも手でしょう。

ただし、機種によっては増えないシロモノもいるようなので、最終手段くらいに考えたほうが良いです。


AndroidManifest.xml


<application
android:name="jp.ogwork.sample.HogeApplication"
android:label="@string/app_name"
android:icon="@drawable/icon"
android:largeHeap="true" >
....


android:largeHeap="true"

を一行添えてあげるだけです。簡単。

以上です。