13

Androidでメモリリークを回避する方法について多くの記事を読みましたが、それが正しいかどうかはまだよくわかりません。

  1. 私のアプリケーションは単一ので構成されていActivityます。
  2. そのアクティビティにはプライベートメンバーまたは静的メンバーがありません。すべてのコードは内から開始されますonCreate()
  3. Contextには、静的インスタンスがaまたはViewsへの参照を保持することがある自己完結型の静的クラスがあります 。私のonDestroy()メソッドでは、これらのインスタンスをすべてnullに設定しました。
  4. 私はすべてをリサイクルしますBitmap

Q1:それで十分ですか?

私を混乱させるのは、ネット上で見つけることができるノーゴーの典型的な例です(http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/):

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);

  TextView label = new TextView(this);
  label.setText("Leaks are bad");

  setContentView(label);
}

onCreate終わったらすぐlabelにスコープから外れてGCになると思いました。

Q2:これはどのようにしてメモリリークを引き起こすのですか?

私のアクティビティは基本的に次のようになります。

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /* Statics */
    AssetUtils.initIndex(this);
    BitmapLoader.startInstance(this);

    /* frame */
    ViewGroup frame = (ViewGroup) getLayoutInflater().inflate(R.layout.frame, null);
    this.setContentView(frame);

    /* create controller */
    Controller controller = new Controller(frame, getLayoutInflater());

    /* START */
    controller.start();
}

@Override
public void onDestroy() {
    super.onStop();

    /* Statics */
    AssetUtils.destroyInstance();
    BitmapLoader.destroyInstance();
}

内部では、手動で作成したなどに渡すために使用をController取得することがあります。すべてがに戻るクラスのメンバー変数にのみ、静的にどこかに格納されることはありません。ContextView#getContext()ViewController

Q3:見落としているものはありますか?

4

1 に答える 1

23

Q1。あなたはこれを文脈から外しました(冗談は意図していません:)

元の記事を見ると、実際には、ビットマップフィールドが導入されている次のコードフラグメントでリークが発生しています。次に、ローマンはそれがリークする理由を明確に説明します。あなたが示したコードはリークしません。

http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/

Q2。アクティビティコンテキストは、他に選択肢がない場合にのみ使用し、参照するアクティビティのスコープよりも広いスコープを持つものでの参照を許可しないでください。あなたが示したコードは、あなたのアクティビティよりも広いスコープを持つコンテキスト参照を持っているものはないので、私が見る限りリークしません。あなたはそれがそうだと思いますか?

Q3。ビットマップ、静的参照を使用しているかどうかにかかわらず、私はonPause()のビューからビットアンプのバインドを解除する習慣があります(onDestroy()は保証されていませんが、破壊されているかのように無関係であるため、プロセスが強制終了されるため、GC心配する必要はありません)。リンク先の記事では、これを行う方法についても説明しています。ビットマップを処理するアクティビティのテンプレートパターンにしました。

[編集]

申し訳ありませんが、確認しました。この記事では、バインドを解除する方法については説明していません。私が使用するパターンは次のとおりです。

@Override
protected void onPause()
{
        super.onPause();

        unbindDrawables(findViewById(R.id.mainLayout));
        System.gc();
}


@Override
protected void onDestroy()
{
        super.onDestroy();

        unbindDrawables(findViewById(R.id.mainLayout));
        System.gc();
}

private void unbindDrawables(View view)
{
        if (view.getBackground() != null)
        {
                view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup && !(view instanceof AdapterView))
        {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
                {
                        unbindDrawables(((ViewGroup) view).getChildAt(i));
                }
                ((ViewGroup) view).removeAllViews();
        }
}

mainLayoutアクティビティレイアウトのルートビューです。

アクティビティを手動でfinish()する可能性があるため、onDestroy()を含めます。

ノート。system.gc()の呼び出しは複雑な問題であるため、省略したい場合があります。ここでは、主にパフォーマンスに関係して、なぜそれが良いことではないのかについて、いくつかの良い議論があります。ただし、私の見解では、アクティビティが破棄されている場合、GCを実行するのに今が良い時期であることを示唆しても害はありません。それを不必要に呼び出すことの非効率性は、アクティビティを破壊するオーバーヘッドで失われます。

于 2013-02-07T19:50:41.103 に答える