1

C# でサービス アプリケーションを作成しています。2秒ごとにタイマーでアクション(配列)を作成しようとしています。しかし、関数呼び出しが終了した後、私のタイマーは死んでしまいます。

私の始まり:

   ...
   Alaram  Fi = new Alaram();
   Fi.AgentStart();
   GC.KeepAlive(Fi);
   ...

私のアララムクラス:

    public void AgentStart()
    {
        ...
        int i = 0;
        Timer[] timers = new Timer[count];

        while (myReader.Read())
        {
            timers[i] = new Timer(coba, myReader["DeviceId"], 0, 2000);
            i++;
        }
        GC.KeepAlive(timers);

     }

私の行動:

 public void coba(object id)
 {
        ...

        int sec = Convert.ToInt32((string)myCommand.ExecuteScalar());
        sec++;

        myCommand = new SqlCommand("UPDATE Roles  SET  Value ='" + sec.ToString() + "' WHERE   Name = 'Fire" + id.ToString() + "'", ibmsConnect);
        myCommand.ExecuteNonQuery();
        ...
  }

私のタイマーは最大36回しか実行されず、その後タイマーはもう実行されませんでした。サービスが停止するまでライブを維持する必要があります

誰かが私のタイマーが停止し続ける理由を知っていますか??

4

2 に答える 2

3

GC.KeepAliveメソッド内の配列である、宣言された(または格納された)スコープのタイマーでの積極的なガベージコレクションのみを防止しますAgentStart。配列とタイマーがスコープ外になると(メソッドの実行が完了すると)、ガベージコレクションによって収集が開始されます。

スコープ内にとどまる場所で配列を宣言する必要があります。これを行う1つの方法は、配列を静的としてマークし、クラスレベルに配置することです。次に、クラスの静的コンストラクターで配列に割り当てるタイマーをインスタンス化します。これは彼らを生かし続けるはずです。

于 2012-04-28T03:30:09.103 に答える
2

のドキュメントによるとKeepAlive

このメソッドは obj パラメーターを参照し、ルーチンの開始から実行順序でこのメソッドが呼び出される時点まで、そのオブジェクトをガベージ コレクションの対象外にします。このメソッドは、obj が使用可能でなければならない命令の範囲の最初ではなく、最後にコーディングしてください。

KeepAlive メソッドは操作を実行せず、パラメーターとして渡されたオブジェクトの有効期間を延長する以外に副作用はありません。

つまり、 GC が呼び出し前に変数KeepAliveを収集しないように、変数を参照するだけで何もしません。これは、スコープ外になるまで保持する必要があるローカル変数に役立ちます。簡単な例を次に示します。KeepAlive

void DoSomething()
{
    Timer myTimer = ...;
    // long-running operation
    GC.KeepAlive(myTimer);
}

がなければKeepAlive、このメソッドは、Timer が実行時間の長い操作の途中で収集されるポイントまで最適化される可能性があります。

簡単に言えKeepAliveば、オブジェクトを呼び出し後に保持せず、呼び出し前にのみ保持します。

オブジェクトが収集されないようにするには、オブジェクトへの参照を保持する必要があります。これは、クラスのフィールドに格納することで簡単に実現できます (クラス インスタンス自体がスコープ外に出ない限り)。

于 2012-04-28T04:32:25.627 に答える