[セットトップ]Andriod-メモリの漏洩-分析-ソリューション

11428 ワード

Activityリーク
私たちが最初に修復しなければならない問題はActivityの漏洩です.まず、メモリの漏洩がどのように発生しているかを見てみましょう.Activity漏洩は通常メモリ漏洩の一種である.どうして漏れたの?未使用のActivityの参照を持っている場合は、Activityのレイアウトも持っているので、自然とすべてのViewが含まれています.最も厄介なのは静的参照を持つことです.ActivityとFragmentにはライフサイクルがあることを忘れないでください.静的参照を持つと、ActivityとFragmentはゴミ回収機でクリーンアップされません.これが静的参照が危険である理由です.
m_staticActivity = staticFragment.getActivity()

私はこのようなコードを何度も見たことがあります.
また、Listenerを漏らすこともよくあります.例えば、私は次のコードを持っています.LeakActivityActivityから継承されています.NastyManagerという単一の例があります.addListener(this)でActivityをListenerとNastyManagerとしてバインドすると、悪いことが起こります.
public class LeakActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    NastyManager.getInstance().addListener(this);
  }
}

このようなバグを修復するには、実はかなり簡単で、あなたのActivityが破棄されたときに、彼とNastyManagerをバインド解除すればいいのです.
@Override
public void onDestroy() {
  super.onDestroy();

  NastyManager.getInstance().removeListener(this);
}

上記の解決策に比べて、私たちは自然にもっと良いものがあります.例えば、私たちは本当に単例を使う必要がありますか?通常、必要ありません.しかし、時には本当に必要かもしれません.私たちはバランスと設計をしなければなりません.しかし、いずれにしても、Activityが破棄された場合、Activityへの参照は単一の例で削除されることを覚えておいてください.次に、内部クラスであれば何が起こるかについて議論します.たとえば,Activityに非常に短い非静的Handlerがある.
短いように見えますが、まだ生きている限り、それを含むActivityは生きています.もしあなたが私を信じないなら、VMで試してみてください.これがもう一つのメモリ漏洩の例であるActivity内部のHandlerです.
public class MainActivity extends Activity {
  //...
  Handler handler;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...
    handler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
              }
  }
}

Handlerはよく使われるクラスで、非同期、スレッドセキュリティなどです.次のようなコードがあれば、何が起こるのでしょうか.handler.postDeslayed、delay時間が何時間だと仮定しますか...これは何を意味しますか?handlerのメッセージがまだ処理されていない限り、それはずっと生きていて、そのActivityを含めて生きていることを意味します.修復方法を考えてみましょう.修復案はWeakReference、いわゆる弱引用です.ゴミ回収機は回収の際、弱引用を無視してしまうので、それを含むActivityは正常に整理されます.大体のコードは以下の通りです.
private static class MyHandler extends Handler { 
  private final WeakReference<MainActivity> mActivity; 
  // ...
  public MyHandler(MainActivity activity) {
    mActivity = new WeakReference<MainActivity>(activity);
    //... 
  }

  @Override
  public void handleMessage(Message msg) { 
  }
  //...
}

要約すると、Handlerのように内部非静的クラスは所属クラスから離れて単独で生存できない内部クラスがあり、Androidでは通常Activityです.コードの内部クラスを見て、メモリの漏洩が発生していないことを確認します.
非静的内部クラスに比べて、静的内部クラスを使用することが望ましい.違いは、静的内部クラスが属するクラスに依存せず、異なるライフサイクルを持っていることです.似たような原因でメモリが漏れるのをよく見ます.
Activityの漏洩を避けるにはどうすればいいですか? 
すべての静的参照を削除します.
EventBusを用いてListenerをデカップリングすることを考慮した.
不要なときにListenerのバインドを解除することを覚えています.
できるだけ静的内部クラスを使用します.
Code Reviewをします.個人的な経験:Code Reviewはメモリの漏れを早く発見することができます.
あなたのプログラムの構造を理解します.
MAT,Eclipse Analyzer,LeakCanaryのようなツールでメモリを解析します.
Callbackでログを印刷します.