0

したがって、メモリリークに関する読み取り/調査から、メモリリークを回避するために、すべての内部クラスを静的にすることをお勧めします。ただし、SDKサンプル(具体的にはTicTacToeLib)を見ると、静的内部クラスを使用せずにコールバックを実装しています。これによりメモリリークが発生しますか?そうでない場合、なぜですか?

private Handler mHandler = new Handler(new MyHandlerCallback());


private class MyHandlerCallback implements Callback {
        public boolean handleMessage(Message msg) {
            if (msg.what == MSG_COMPUTER_TURN) {

                // Pick a non-used cell at random. That's about all the AI you need for this game.
                State[] data = mGameView.getData();
                int used = 0;
                while (used != 0x1F) {
                    int index = mRnd.nextInt(9);
                    if (((used >> index) & 1) == 0) {
                        used |= 1 << index;
                        if (data[index] == State.EMPTY) {
                            mGameView.setCell(index, mGameView.getCurrentPlayer());
                            break;
                        }
                    }
                }

                finishTurn();
                return true;
            }
            return false;
        }
    }
4

2 に答える 2

1

Messageはい、このサンプルがキューに保持されている場合、リークが発生します。ただし、通常はかなり短い時間に制限されるため、それほど深刻なリークではありません。

しかし、リークを防ぐかなり簡単な方法があります。

次の 2 つのクラスをプロジェクトに追加します。

/** Callback that decouples the wrapped Callback via WeakReference */
public class SafeCallback implements Handler.Callback {
    private final WeakReference<Handler.Callback> mCallback;
    public SafeCallback(Handler.Callback callback) {
        mCallback = new WeakReference<Handler.Callback>(callback);
    }
    @Override
    public boolean handleMessage(Message msg) {
        Handler.Callback callback = mCallback.get();
        if (callback != null)
            return callback.handleMessage(msg);
        // else warn, return true, ..?
        return false;
    }
}

/** replacement for anonymous inner Handler implementations */
public abstract class SafeHandler implements Handler.Callback {
    @Override
    public abstract boolean handleMessage(Message msg);

    public final Handler get() {
        return new Handler(new SafeCallback(this));
    }
    public final Handler get(Looper looper) {
        return new Handler(looper, new SafeCallback(this));
    }
}

Handlerこれで/はほとんど以前と同じように使用できますCallbackが、リークはなくなりました。

だからどちらかのように

public class TestActivity extends Activity {
    private Handler mHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler = new SafeHandler() { // << instead of new Handler() {
            @Override
            public boolean handleMessage(Message msg) {
                // handle message
                return false;
            }
        }.get(); // << Notice this added .get()
    }
}

または好き

public class TestActivity2 extends Activity implements Handler.Callback {

    private Handler mHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler = new Handler(new SafeCallback(this)); // << wrapped in SafeCallback
    }

    @Override
    public boolean handleMessage(Message msg) {
        // handle message
        return false;
    }
}

のリークの問題Handlerは、各Message/ Runnable(実際には a でラップされているMessage) がターゲットであることを認識していることです。つまり、Handlerorへのハード参照がありCallbackます。また、そのターゲットが非静的内部クラスである場合、外部クラスへの暗黙的なハード参照があり、通常はActivity.

つまり、 がMessagesキューに入れられている限りHandler、全体Activityをガベージ コレクションすることはできません。

この問題を解決するには、 からMessageへのハード参照のチェーンをActivity切断する必要があります。SafeCallbackクラスは、あなたWeakReferenceActivity.

つまり、 はMessageハード参照になりましSafeCallbackたが、そこにバインドされている部分はガベージ コレクションできるようになりました。それが起こった場合、結果Handler.Callback callback = mCallback.get();は単純に破棄されます。とにかく、これ以上有用なターゲットはありません。それ自体はまだリークしていますが、それはほとんど空のクラスであるため、問題は発生しません。nullMessageSafeCallback

于 2012-11-15T00:24:37.957 に答える
-1

言語自体が何をしているのかではなく、解決しようとしているユースケースの観点からアプローチします。「ネストされたクラス」(内部クラスは静的にできないため、内部クラスではない)がその親クラスで非静的メソッドを呼び出すか、非静的メンバーを読み取ることができる必要がある場合、選択肢はあまりありませんが、非静的にします。親クラスの非静的リソースのいずれにもアクセスしないで済む場合は、必ずアクセスしてください(とにかく、その方法でメモリを節約できます)。ただし、メモリリークが心配で、例のようにネストされたクラスをプライベートにする場合は、本当にすべきです. そのクラスのインスタンスは親クラスに対してローカルでのみ作成できるため、心配する必要はありません (ネストされたクラスのインスタンスへの参照を保持する親クラスの静的メンバーを作成しない限り、その場合、そのオブジェクトは親クラスが VM によってアンロードされるまで)。要約すると、ネストされたクラスが静的または非静的として宣言されているかどうかについて個人的にはあまり心配しませんが、メモリリークが心配な場合は、そのクラスのインスタンスのライフサイクルにもっと焦点を当てます。

于 2012-11-15T00:20:13.880 に答える