15

のドキュメントにSystem.Threading.Timerは、ガベージ コレクションを回避するためにライブ参照を保持する必要があると記載されています。しかし、どこでそれを行うべきですか?私mainは非常に単純で、参照をどこに保持すればよいかわかりません。

class Program {
    static void Main() {
        new System.Threading.Thread(myThreadStart).Start();
        new System.Threading.Timer(myTimerCallback, new MyStateObject(), 0, 5000);
    }
}

アプリケーションの最後までフィールドが収集されないと仮定してstatic、クラス内のフィールドに参照を保持することを考えました。しかし、これが最善の方法であるかどうかはわかりませんので、アドバイスをいただければ幸いです。Programstatic

4

3 に答える 3

18

Timer がアプリケーション レベルのオブジェクトである場合、それを Main クラスのプライベートな静的メンバーにすることに問題はありません。とにかく、それは私がすることです。

于 2009-01-25T08:58:39.200 に答える
12

編集:私の最初の答えはゴミです。本当にゴミ。なぜゴミなのかを説明するためにここに残しておきました-コメントにありますが、答えがあれば削除されていたはずです。

GC.KeepAlive は、呼び出し後まで参照がルートとして扱われることを確認するだけです。この回答の下部にあるコードでは、GC.KeepAlive メソッドがすぐに呼び出され、タイマーは引き続きガベージ コレクションの対象になります。新しく作成されたスレッドはフォアグラウンド スレッドであるため、アプリはそれが存続している限り実行されます (一方、タイマーはプログラムの終了を妨げないバックグラウンド スレッドを使用します)。これは、Main メソッドは終了しますが、アプリケーションは実行し続ける必要があることを意味します。

おそらく、新しいスレッドを作成してからメイン スレッドを終了させるよりも、メイン スレッドで実行する方が簡単な解決策になるでしょう。myThreadStartつまり、簡単な解決策は次のようになります。

using System.Threading;

class Program {
    static void Main() {
        Timer timer = new Timer(myTimerCallback, 
                                new MyStateObject(), 0, 5000);
        myThreadStart();
        GC.KeepAlive(timer);
    }
}

ただし、実際のコードはもっと複雑だと思います-その場合、他の回答で提案されているようにプライベート静的変数を使用するのがおそらく道です。使い方にもよるだろうけど。個人的には、代替手段 (上記のような) がある場合に何かが収集されるのを防ぐためだけに静的フィールドを作成しないことを好みますが、それが事実上唯一の方法である場合もあります。

元の(悪い)答え:

本当にメインに割り当てたい場合は、GC.KeepAliveを使用できます。

using System.Threading;

class Program {
    static void Main() {
        new Thread(myThreadStart).Start();
        Timer timer = new Timer(myTimerCallback, 
                                new MyStateObject(), 0, 5000);
        GC.KeepAlive(timer);
    }
}
于 2009-01-25T07:59:57.230 に答える
4

あなたのクラスのprivate staticフィールドを保持しても問題ないと思います。

ガベージ コレクターで遊ぶのではなく、この参照を静的フィールドとして保持します。

于 2009-01-25T08:01:57.070 に答える