When does a System.Timers Timer get disposed? [duplicate] - c#

which is the right approach to use a System.Timers.Timer?
I mean... I create the timer, set the interval and the method to be called on the Elapsed event.
double ms = 1000;
var t = new System.Timers.Timer(ms);
t.AutoReset = false;
t.Elapsed += (sender, e) => { runTask(); };
t.Start();
What next? Should a call dispose on the Timer? I suppose I can't, or the Elapsed event will never occur.
Should I register the Timer in some global variable to avoid to lose references to it and so the GC could dispose the timer before the Elapsed is called?
And if so, how can I dispose the Timer once the Elapsed event has been handled (thus my task has been executed)?

If you are using Timers during a long running process (e.g. a web application or a windows service), if you don't want to get a memory leak, you need to ensure that you un-subscribe from the Timer's elapsed event handler if you want the garbage collector to be able to reclaim the memory allocated for the Timer object.
System.Timers.Timer implements IDisposable and the guidelines here are that if you have a class that implements IDisposable, any class that has a dependency on an object implementing IDisposable should implement IDisposable itself and call the objects Dispose() method when it itself is called.
A perfect example of this is indeed with System.Timers.Timer. This uses System.Threading.Timer underneath the covers and if you look in reflector you can see the following for the Dispose method on System.Timers.Timer
public void Dispose()
{
this.timerBase.Dispose();
}
Here, timerBase is simply an instance of System.Threading.Timer and therefore the Dispose call cascades down to all dependencies of the class that implement IDisposable.

A short answer is you don't need to do anything. It will be collected by the Garbage Collector when function goes out of scope. If you want it available then declare it in class instead.
Usually when you declare a timer out in class level it is collected by GC when the Class is Disposed. However when you have your timer declare in a Function then the Timer still runs but if you are executing a very long process then GC can Aggressively Dispose it so you will need to use
GC.KeepAlive(youtimer_Instance);
Have a look at the end of the Timer's Documentation for reference to this scenario.
The Comments in the sample code says:
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.

You should call t.Stop() in the Close/Unload of your form/page or anywhere you seem fit. If you leave it running, it will utilize resources unnecessarily and also you might get exceptions while closing the application.

Related

How to prevent System.Threading.Timer get garbage collected in UWP?

I'm trying to implement Undo function in my app. I have code like this Timer timer = new Timer(UndoDeleteTimerFinish, email, UndoBannerDisappearTime, Timeout.Infinite); and UndoDeleteTimerFinish() will make the banner disppear. However, sometimes the banner will stuck on the screen and I found that in this kind of scenario, UndoDeleteTimerFinish() won't be called. I think the timer must be GC collected. I'm wondering how to prevent timer get GC collected and at the same time be responsive and allow user to interact with the app.
The timer has a reference to the object that defines UndoDeleteTimerFinish. If that object's only refrence is to the Timer and vice-versa they will both be eligible for garbage collection.
Quick and dirty fix is to have an object that is not garbage collected hold a reference to your Timer.
class ObjectNotGettingGarbageCollected{
Timer _timer; //won't be GC'd
SomeMethod(){
_timer = new Timer(UndoDeleteTimerFinish, email, UndoBannerDisappearTime, Timeout.Infinite)
}
}
Also as long as the state object (email in you case) is referenced somewhere, the CLR keeps the timer in its timer queue and the timer object won't get garbage collected. So I would check what is the status of the 'email' object which you pass as the state parameter to your Timer.
More about this here:
The System.Threading.Timer constructor has several overloads; all except one take a state parameter which is passed to the TimerCallback delegate when the timer fires.
It turns out that this state parameter (and the TimerCallback delegate) have an interesting effect on garbage collection: if neither of them reference the System.Threading.Timer object, it may be garbage collected, causing it to stop. This is because both the TimerCallback delegate and the state parameter are wrapped into a GCHandle. If neither of them reference the timer object, it may be eligible for GC, freeing the GCHandle from its finalizer.
The single-parameter constructor does not suffer from this problem, because it passes this for the state (not null). Most real-world usage of System.Threading.Timer either references the timer from the callback or uses the timer for the state, so this interesting garbage collection behavior will probably not be noticed.
http://blog.stephencleary.com/2011/07/systemthreadingtimer-constructor-and.html

Using Dispose() method

Why I see "Hello" words many times when I add timer.Dispose() to my code in release mode. Without timer.Dispose() I see "Hello" once. Thanks.
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Method(object state)
{
Console.WriteLine(state);
GC.Collect();
}
static void Main()
{
var timer = new Timer(Method, "Hello", 0, 200);
Console.ReadLine();
timer.Dispose();
}
}
}
You see it once because the garbage collector has collected the timer object.
Since there are no more references to it that is considered "live" the garbage collector is free to do so.
In release mode, and when no debugger is attached, the JITter builds up knowledge of where local variables are used in a method. Once a variable is no longer used, it is no longer considered to be a root if the method is currently executing below that point. As such, the garbage collector can collect the timer object. However, before it can do so it must finalize the object, which destroys the underlying timer object and stops it from executing.
In debug builds, the scope of all local variables are artificially extended to be the entire method, so that if you place a breakpoint in the method you can inspect variables, even if the program would no longer actually require that variable to exist.
When you added the call to dispose, you extended the lifetime of the variable, and thus prevented the garbage collector from collecting your timer object.
Since you provoke a garbage collection in the timer event handler method, you effectively destroy the timer yourself in this case. When you extended the lifetime of the variable by adding in the call to Dispose, the garbage collector still runs as part of your timer event handler, but it cannot yet collect the timer, so it keeps running.
The answer left here by Hans Passant describes this much better than my meager attempt above:
Understanding Garbage Collection in .NET.
I suspect it's because GC.Collect will not collect the timer object when it's still referenced below the current line of code.
timer.Dispose(); is acting like GC.KeepAlive(timer); in this instance.
If you remove both the Dispose and the GC.Collect(), you will get a few "Hello"s, and then the GC will decide to collect by itself, and you'll get no more.

How does the Garbage Collector KeepAlive method work with a timer?

I've just stumbled across some code that uses the GC.KeepAlive() method and I am trying to understand how it works. For example, in this code:
Timer timer = new System.Timers.Timer(5000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Enabled = true;
GC.KeepAlive(timer);
In this code, my understanding is that a Timer object is created, which spawns a thread that runs every 5 seconds. Next, the GC line is ran. Then the method exits, destroying the timer when garbage collection runs.
The KeepAlive only keeps it alive prior to the call to KeepAlive, which it looks to me is about 0.0000001 seconds and it won't be destroyed there anyway since there is a local reference to it (unless it's destroying it because nothing else happens to the timer object?)
Either way, by the time the 5000 interval is hit the method will have ended ages ago and it's very likely the timer is destroyed. So what's the purpose of that line?
So what's the purpose of that line?
Nothing. You shouldn't be using it as it's not helping anything. That code was probably written by someone not particularly familiar with how the Timer class works.
Internally the Timer class will use entirely different means of ensuring that it is not garbage collected before it should be. See this question for the details.
In this context, there's no reason for that line. The only time it can help is if there is a lot of code between the timer.Enabled and the call to KeepAlive, as in:
timer.Enabled = true;
// lots of code here that does
// things that take some time
GC.KeepAlive(timer);
}
That will prevent the garbage collector from collecting the timer before the method ends. Without the call to KeepAlive, the GC could decide that timer isn't used any more after Enabled is set, and it could do an early collection.
If you want a persistent timer, you have to declare it at class scope.

Will this get Garbage Collected?

Is this a valid way to use a Lambda as an EventHandler? It seems to me that the handler has been correctly removed and that the garbage collector should clean this up. However, I haven't seen anyone else do it this way, so I thought I'd better double check.
Along the same lines, what's the best tool (preferably free) to use to test whether this is in fact being garbage collected?
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(10);
EventHandler callback = null;
callback = (s, e) =>
{
timer.Stop();
timer.Tick -= callback;
};
timer.Tick += callback;
timer.Start();
A DispatcherTimer is kept alive by the Dispatcher class, it keeps a List<DispatcherTimer> internally that stores a reference to any timer that's enabled. As soon as you Stop() the timer, the object gets removed from that list, making it eligible for garbage collection if you don't store any additional reference to it. Which you don't in this case, the timer reference is a local variable.
You cannot get a finalizer on the auto-generated class that implements the lambda. Next best thing is to simply run this code a billion times. If you don't get runaway member consumption and OOM then it obviously doesn't leak. You'll want to make the Interval shorter so it doesn't take until Christmas, 15 msec is good. Use a Timer to call the method so you don't get too many active timers at the same time and allow the dispatcher to do its job.
Yes, the callback will be eligible for garbage collection after the callback has executed once. This is a reasonable way of subscribing to an event in order to execute the handler just once.
It's tough to prove that the delegate will be garbage collected - or indeed that the object used to hold the captured variables callback and timer will be garbage collected, admittedly... you'd really want to put a finalizer there (which affects garbage collection itself, of course), but you can't as it's generated code.

Do Timer object get GC-ed when no other object references them?

Can an object containing an active Timer (System.Timers.Timer) be garbage collected, if no other object is referencing it?
There are two basic ways that a Timer stays referenced even if you don't store a reference somewhere:
As long as the timer is enabled. There's an underlying System.Threading.Timer that actually generates the event. The CLR keeps a list of active timers, the callback delegate object of them keeps the Timer referenced.
By the Elapsed event handler if it is not static. That extends the lifetime of the Timer instance to at least the lifetime of the class object that contains the Elapsed event handler.
There is no failure mode here. The only possible way to get a reference back to the timer is through the Elapsed event handler's sender argument. If you disable the timer then there is no longer a way to get a reference so it is appropriate for the object to be collected.
A fairly classic way to get in trouble with this Timer and lose Elapsed events is when you have the AutoReset property set to false. A very nasty issue is that any exceptions raised in the Elapsed event handler are swallowed without any diagnostic. Which will bypass the call you'd have to restart the timer at the end. Do favor System.Threading.Timer, it doesn't have this problem.
Yes. Timer will be GC'd if left unreferenced, even while running.
The documentation says:
The code contains declarations of the timer variable at the class level and inside Main. To see how aggressive garbage collection can affect a timer that is declared inside a long-running method, you can comment out the class-level declaration and uncomment the local variable. To keep the timer from being collected, uncomment the GC.KeepAlive method at the end of Main.

Categories