Androidプログラミングでメモリ漏洩を避ける方法のまとめ

3236 ワード

Androidのアプリケーションは最大16 mのメモリを消費するように制限されており、少なくともT-Mobile G 1ではそうである(もちろん現在では数百兆のメモリが使用可能である――訳者注).これには、電話自体が占有しているものと、開発者が使用できるものの2つの部分が含まれています.すべてのメモリを占有するつもりがなくても、他のアプリケーションが実行中にアプリケーションを閉じないように、メモリをできるだけ少なく使用する必要があります.Androidがメモリに保持できるアプリケーションが多ければ多いほど、ユーザーはアプリケーションを切り替えるときに速くなります.私の仕事として、Androidアプリケーションのメモリ漏洩の問題をよく研究しました.多くの場合、同じエラーによって引き起こされます.それは、コンテキスト(Context)に対して長い間参照を維持しています.
Androidでは、コンテキスト(Context)が多くの操作として使用されていますが、ほとんどはリソースのロードとアクセスです.これは、すべてのwidgetがそれらのコンストラクション関数でコンテキスト(Context)パラメータを受け入れることです.適切なAndroidアプリケーションでは、アクティビティ(Activity)とアプリケーション(Application)の2つのコンテキストを使用することができます.アクティビティ(Activity)は、通常、コンテキスト(Context)パラメータを必要とするクラスまたはメソッドに渡されます.
 
  
@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);
 
  TextView label = new TextView(this);
  label.setText("Leaks are bad");
 
  setContentView(label);
}

これは、そのViewにアクティビティ全体(Activity)への参照があり、このアクティビティ(Activity)で保持されているすべてのオブジェクトに対して参照が保持されていることを意味します.通常は、View全体の階層とそのすべてのリソースが含まれます.したがって、コンテキスト(Context)を「漏洩」した場合(ここで「漏洩」は、参照を維持し、GCを組織して収集することを意味します)、大量のメモリ漏洩をもたらします.注意が足りない場合は、アクティビティ全体を「漏らす」ことは簡単です.
画面の方向が変わると、現在のアクティビティがデフォルトで破棄され、新しい状態が作成され、その状態が維持されます.その結果、AndroidはアプリケーションのUIをリソースから再ロードします.今想像してみてください.アプリケーションを書いて、非常に大きなビットマップを持っていて、回転するたびに再ロードしたくありません.回転するたびに再ロードしない最も簡単な方法は、静的フィールドに保存することです.
 
  
private static Drawable sBackground;
 
@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);
 
  TextView label = new TextView(this);
  label.setText("Leaks are bad");
 
  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);
 
  setContentView(label);
}

このコードは非常に速く、同時に間違っています.最初の画面角度が変更されたときに作成された最初のアクティビティ(Activity)が漏れています.Drawableがビューに追加されると、drawableのコールバックに設定されます.上記のコード・スライスでは、このDrawableがTextViewに対して参照を持っていることを意味し、このTextViewはActivity(Contextオブジェクト)に対して参照を維持していると同時に、このActivityは多くのオブジェクトに対して参照を持っている(これはあなたのコード次第です).
この例はContext漏洩の最も簡単な原因の一つであり、メイン画面のソースコード(unbindDrawables()メソッドの表示)でActivity破棄時に保存したDrawableのコールバックを空に設定することで、この問題を解決することができます.さらに興味深いことに、context漏洩のチェーンを作成することができます.もちろん、これは非常に悪いです.すべてのメモリをすばやく使いこなすことができます.
contextに関連するメモリの漏洩を回避するには、2つの簡単な方法があります.最も明らかなのはcontext自体の範囲外での使用を避けることです.上記の例は、クラス内部の静的参照と、外部クラスへの間接参照が非常に危険であることを示している.2つ目の解決策は、Application Contextを使用することです.このcontextはあなたのアプリケーションに伴って存在し、Activityのライフサイクルに依存しません.contextが必要な長寿命サイクルのオブジェクトを維持する計画がある場合は、Applicationオブジェクトを考慮してください.Contextを呼び出すと便利ですgetApplicationContext()またはActivity.getApplication()を取得します.
要するにcontextに関連するメモリの漏洩を避けるために、以下の点を覚えておいてください.
1.Activity Contextに対して長寿命期間の参照を保持しない(Activityに対する参照はActivity自身のライフサイクルと同じであるべきである).アクティブコンテキスト(context-activity)の代わりにアプリケーションコンテキスト(context-application)を使用してみます.それらのライフサイクルを制御できない場合は、アクティブ(Activity)で静的でない内部クラスの使用を避け、静的クラスの使用、および弱い参照をアクティブ(Activity)の内部に使用します.この問題に対する解決策は静的内部クラスと弱い参照(WeakReference)の外部クラスを用いることである.View RootとそのW内部類のように実現されています.4.ゴミ回収器はメモリの漏洩に対して100%保険ではありません.