2011-02-10 2 views
3

Quelle est la bonne approche pour utiliser un System.Timers.Timer? Je veux dire ... Je crée la minuterie, définissez l'intervalle et la méthode à appeler sur l'événement écoulé.System.Timers.Timer cycle de vie

double ms = 1000; 
var t = new System.Timers.Timer(ms); 
t.AutoReset = false; 
t.Elapsed += (sender, e) => { runTask(); }; 
t.Start(); 

Et ensuite? Un appel doit-il être éliminé par la minuterie? Je suppose que je ne peux pas, ou l'événement Elapsed ne se produira jamais. Est-ce que je devrais enregistrer le Timer dans une variable globale pour éviter de perdre des références à celui-ci et ainsi le GC pourrait disposer du timer avant que le Elapsed ne soit appelé? Et si oui, comment puis-je disposer du Timer une fois que l'événement Elapsed a été traité (donc ma tâche a été exécutée)?

Répondre

1

Une réponse courte est que vous n'avez rien à faire. Il sera collecté par le récupérateur de place lorsque la fonction est hors de portée. Si vous le souhaitez, déclarez-le en classe à la place.


Habituellement, lorsque vous déclarez une temporisation au niveau de la classe, elle est collectée par le GC lors de la mise au rebut de la classe. Toutefois, lorsque vous avez votre minuterie racontons dans une fonction puis la minuterie fonctionne encore, mais si vous exécutez un processus très long alors GC peut Agressivement Evacuer si vous devez utiliser

GC.KeepAlive(youtimer_Instance); 

Jetez un oeil à la fin de le Timer's Documentatio n pour référence à ce scénario.

Les commentaires dans le code exemple dit:


     Normally, the timer is declared at the class level, 
     so that it stays in scope as long as it is needed. 
     If the timer is declared in a long-running method, 
     KeepAlive must be used to prevent the JIT compiler 
     from allowing aggressive garbage collection to occur 
     before the method ends. 
+0

Cela peut créer un problème si le temporisateur a été créé sur le formulaire A et l'utilisateur quitte l'application (déclenchera une exception si la tâche tente d'accéder à un contrôle de formulaire, il m'est arrivé une fois). –

+0

@ Mohib Sheth: ce que j'ai répondu est de savoir comment protéger Timer d'être disposé .. pour l'arrêter évidemment, vous devrez appeler Stop(). Également préférable si vous pouvez vous désinscrire de votre gestionnaire d'événements lorsque cela est nécessaire. Alexis l'a expliqué .... –

+0

Le commentaire de code que vous avez cité n'est plus présent dans la documentation de Timer, d'ailleurs. –

0

Vous devriez appeler t.Stop() dans la fenêtre Fermer/Décharger de votre formulaire/page ou n'importe où vous semblez approprié. Si vous le laissez en cours d'exécution, il utilisera des ressources inutilement et vous pourriez également obtenir des exceptions lors de la fermeture de l'application.

4

Si vous utilisez minuteries lors d'un long processus en cours d'exécution (par exemple, une application Web ou un service Windows), si vous ne voulez pas obtenir une mémoire fuite, vous devez vous assurer que vous vous désinscrivez du gestionnaire d'événements du temporisateur si vous voulez que le garbage collector puisse récupérer la mémoire allouée pour l'objet Timer. System.Timers.Timer implémente IDisposable et les instructions ici sont que si vous avez une classe qui implémente IDisposable, toute classe qui dépend d'un objet implémentant IDisposable doit implémenter IDisposable elle-même et appeler la méthode Objects Dispose() quand c'est lui-même appelé.

Un exemple parfait de ceci est en effet avec System.Timers.Timer. Celui-ci utilise System.Threading.Timer sous les couvertures et si vous regardez dans le réflecteur vous pouvez voir ci-dessous pour la méthode Dispose sur System.Timers.Timer

public void Dispose() 
{ 
    this.timerBase.Dispose(); 
} 

Ici, timerBase est tout simplement une instance de System.Threading. Timer et donc l'appel Dispose descend en cascade vers toutes les dépendances de la classe implémentant IDisposable.

+0

+1 pour souligner les besoins de désabonnement – themarcuz