15

Android のライブ壁紙でメモリ リークが発生しているようです。画面を回転させるたびに、収集されるメモリ ガベージの量が 50kb ずつ増加し、元に戻りません。予定された未来が原因かもしれないと思うので、そうなるかどうかシナリオを提示します。

次のメンバーを持つクラス (Foo と呼びましょう) があるとします。

private ScheduledFuture<?> future;
private final ScheduledExecutorService scheduler = Executors
        .newSingleThreadScheduledExecutor();

private final Runnable runnable = new Runnable() {
    public void run() {
        // Do stuff
    }
};

そして今、あなたは予定された未来を設定します

future = scheduler.scheduleAtFixedRate(runnable, delay, speed,
                TimeUnit.MILLISECONDS);

future は runnable への参照を保持し、runnable は親 Foo オブジェクトへの参照を保持します。これが事実かどうかはわかりませんが、この事実は、プログラム内に Foo への参照が保持されていない場合、スケジュールされた未来があるため、ガベージ コレクターがまだそれを収集できないことを意味するのでしょうか? 私はマルチスレッドが苦手なので、ここに示したコードが、スケジュールされたタスクがオブジェクトよりも長く存続することを意味するかどうか、つまりガベージ コレクトされないことを意味するかどうかはわかりません。

このシナリオで Foo がガベージ コレクションになるのを防ぐことができない場合は、簡単な説明でそのことを伝える必要があります。Foo がガベージ コレクションされないようにする場合、どうすれば修正できますか? する必要がありfuture.cancel(true); future = null;ますか?そのfuture = null部品は不要ですか?

4

3 に答える 3

6
  • メソッドrunが囲んでいるクラスに依存しているFooため、独立して生きることができません。Fooその場合、どのようにgc を作成し、実行可能ファイルを「生きた」状態に保ち、エグゼキューターによって実行されるのかわかりません
  • または、メソッドがクラスrunの状態に依存しないという意味で静的です。この場合、メソッドを静的にすることができ、発生している問題を防ぐことができます。Foo

Runnable の中断を処理していないようです。つまりfuture.cancel(true)、 Runnable を呼び出しても引き続き実行されます。これは、リークの原因であると判断した可能性があります。

Runnable を「割り込みフレンドリー」にする方法はいくつかあります。InterruptedException をスローするメソッド (Thread.sleep()またはブロッキング IO メソッドなど)を呼び出すとInterruptedException、フューチャーがキャンセルされたときにスローされます。クリーンアップする必要があるものをクリーンアップし、中断された状態を復元した後、その例外をキャッチしてすぐに run メソッドを終了できます。

public void run() {
    while(true) {
        try {
            someOperationThatCanBeInterrupted();
        } catch (InterruptedException e) {
            cleanup(); //close files, network connections etc.
            Thread.currentThread().interrupt(); //restore interrupted status
        }
    }
}    

そのようなメソッドを呼び出さない場合、標準的なイディオムは次のとおりです。

public void run() {
    while(!Thread.currentThread().isInterrupted()) {
        doYourStuff();
    }
    cleanup();
}

その場合、while の状態を定期的にチェックするようにしてください。

これらの変更により、 を呼び出すとfuture.cancel(true)、Runnable を実行しているスレッドに割り込み信号が送信され、実行中の処理が終了し、Runnable と Foo インスタンスが GC の対象になります。

于 2012-11-23T18:19:15.557 に答える
0

The future holds a reference to the runnable, and the runnable holds a reference to the parent Foo object. I'm not sure if this is the case, but could this fact mean that if nothing in the program holds a reference to Foo, the garbage collector still cannot collect it because there is a scheduled future?

Its a bad idea to make Foo some sort of transient object that you create often because you should shutdown the ScheduledExecutorService scheduler when your app closes. Thus you should make Foo a pseudo-singleton.

The Garbage collector understands cycles so once you shutdown Foo's executor service you will most likely not have memory issues.

于 2012-11-23T19:36:33.633 に答える