5

DispatcherTimer を使用して時計の目盛りを更新する WPF アプリがあります。

ただし、アプリケーションを約 6 時間実行した後、時計の針の角度が変化しなくなりました。DispatcherTimer が Debug で引き続き起動し、角度値が更新されていることを確認しましたが、画面のレンダリングには変更が反映されません。

また、WPPFerf ツールの Visual Profiler を使用して、Unlabeled Time、Tick (Time Manager)、および AnimatedRenderMessageHandler(Media Content) がすべて CPU のほぼ 80% を消費するまで徐々に増加していることを確認しましたが、メモリは安定して動作しています。

hHandRT.Angle は RotateTransform への参照です

hHandRT = new RotateTransform(_hAngle);

このコードは、約 5 時間の連続実行で完全に機能しますが、その後は遅延し、角度の変更が画面に表示されません。この問題のトラブルシューティング方法に関する提案、またはあなたが知っている可能性のある解決策。

.NET 3.5、Windows Vista SP1 または Windows XP SP3 (どちらも同じ動作を示します)

編集:クロックティック機能の追加

//In Constructor
...
_dt = new DispatcherTimer();
_dt.Interval = new TimeSpan(0, 0, 1);
_dt.Tick += new EventHandler(Clock_Tick);
...

 private void Clock_Tick(object sender, EventArgs e)
        {

            DateTime startTime = DateTime.UtcNow;
            TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(_timeZoneId);
            _now = TimeZoneInfo.ConvertTime(startTime, TimeZoneInfo.Utc, tst);
            int hoursInMinutes = _now.Hour * 60 + _now.Minute;
            int minutesInSeconds = _now.Minute * 60 + _now.Second;
            _hAngle = (double)hoursInMinutes * 360 / 720;
            _mAngle = (double)minutesInSeconds * 360 / 3600;
            _sAngle = (double)_now.Second * 360 / 60;
            // Use _sAngle to showcase more movement during Testing.
            //hHandRT.Angle = _sAngle;
            hHandRT.Angle = _hAngle;
            mHandRT.Angle = _mAngle;
            sHandRT.Angle = _sAngle;

            //DSEffect
            // Add Shadows to Hands creating a UNIFORM light
            //hands.Effect = textDropShadow;
        }

クロックティックであまりにも多くのことが起こっていることに沿って、私は現在、この調整が役立つかどうかを確認しようとしています. 残念ながら、バグが現れるまでに 5 時間かかります :(

  //DateTime startTime = DateTime.UtcNow;
  //TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(_timeZoneId);
  //_now = TimeZoneInfo.ConvertTime(startTime, TimeZoneInfo.Utc, tst);
  _now = _now.AddSeconds(1);
4

3 に答える 3

5

毎回Clockクラスのインスタンスを作成していると言いますか?.NETのタイマーは、ガベージコレクションを防ぐために自分自身をルート化することに注意してください。それらは、自分で停止するまで発火し続け、タイマーティックイベントで参照されるため、Clockオブジェクトを存続させます。

何が起こっているのかというと、作成する時計ごとに別のタイマーを開始するということです。最初は1秒あたり1つのイベントしか発生しませんが、次に別のタイマーを追加して1秒あたり2つを取得し、この方法で累積し続けます。最終的に、TickハンドラーとAnimatedRenderMessageHandlerがCPUで上昇し、それらが停止して画面を更新できなくなるまで表示されます。それはまた、タイマーの発射の頻度を増やすと症状が早く現れる理由を説明します。

修正は簡単である必要があります。Clockオブジェクトの使用が終了したら、DispatcherTimerを停止または破棄するだけです。

于 2009-10-13T04:46:10.393 に答える
1

あなたはそれが DispatcherTimer であり、それに完全に集中していると想定しています。個人的には、タイマー自体と関係があるとは信じがたいですが、タイマーティック内で行っていることと関係があると思います。タイマーが作動するたびに何が起こっているのか、詳しく教えていただけますか?

于 2009-10-12T18:11:45.923 に答える
1
hHandRT.Angle = _hAngle;
mHandRT.Angle = _mAngle;
sHandRT.Angle = _sAngle;

上記のコードをもう一度確認する必要があると思います。

毎秒変更する必要がない場合でも、3 つの変換すべてに対して変換の Angle プロパティを設定しています。分は 60 回ごとに変わり、時間は 3600 秒ごとに変わります。ただし、少なくとも毎秒変化する時間の角度を減らすことができます。

ここで何が起こっているかというと、変換の変更を WPF に要求するたびに、WPF はその要求を優先ディスパッチ キューにキューに入れ、1 秒ごとにさらに多くの変更をプッシュして処理できるようにします。これが、メモリではなく CPU 使用率が増加し続ける唯一の理由です。

詳細な分析:

あなたのコードを見た後、私はあなたの DispatcherTimer_Tick イベントがあまりにも多くの計算を行っているように感じます.Dispatcher スレッドは、ディスパッチャーでカスタムタスクを実行するために CPU をよりビジー状態に保つ場合、イベントルーティングの管理、ビジュアルアップデートなどの多くのことですでに過負荷になっていることを思い出してください.スレッドも毎秒イベントで、保留中のタスクのキューを確実に増やし続けます。

小さな乗算計算だと思うかもしれませんが、Dispatcher スレッドの場合、タイムゾーンの読み込み、時間値の変換などに関してコストがかかる可能性があります。ティックの実行時間をプロファイルして確認する必要があります。

別のスレッドで実行される System.Threading.Timer オブジェクトを使用する必要があります。ティック イベントごとに、必要な最終角度の計算が完了したら、Dispatcher スレッドに渡すことができます。

お気に入り、

Dispatcher.BeginInvoke((Action)delegate(){
   hHandRT.Angle = _hAngle;
   mHandRT.Angle = _mAngle;
   sHandRT.Angle = _sAngle;   
});

これにより、ディスパッチャ スレッドのワークロードを少し減らすことができます。

于 2009-10-14T12:56:13.750 に答える