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

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

Related

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

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.

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.

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.

When are method variables, accessible in an anonymous method, garbage collected?

For instance is it necessary to add a Timer instance to a list as I am doing here to prevent the Timer being garbage collected? Tyically if the callback was not anonymous the aswer is yes, but since it is anonymous i imagine the variables in the method block which are accessible in the anonymous method block will only be garbage collected when the anonymous method completes? In which case no need to save ref as I am doing..:
private static List<Timer> timers = new List<Timer>();
public static void RunCallbackAfter(Action callback, int secondsToWait)
{
Timer t = null;
t = new Timer(new TimerCallback(delegate(object state)
{
SomeThread.BeginInvoke(callback);
timers.Remove(t);
}), null, secondsToWait*1000, Timeout.Infinite);
timers.Add(t);
}
The objects referred to by the captured variables in the anonymous method will not be eligible for garbage collection until the delegate created by the anonymous method is eligible for garbage collection.
However, if it's only the Timer which has a reference to the delegate, and nothing else has a reference to the timer, then I suspect both would be eligible for garbage collection, assuming this is indeed the kind of timer which you need to keep a reference to. (I seem to remember that some timers do require this and some don't. I can't remember which is which.)
Also, if you removed the timers.Remove(t) call from within the anonymous method then it wouldn't be capturing t in the first place. It's only captured variables which have prolonged lifetimes... not every variable in the method which contains the anonymous method.
In general, anonymous functions in C# will keep any local variables that they reference alive until the anon function itself is destroyed. Naturally, removing the remove call in this case would remove the reference, meaning the variable would no longer be kept alive by the callback.
However, this here forms a circular reference; unless there's an outside reference the timer and callback could be destroyed simultaneously. I'm not sure if starting a timer counts as an external reference keeping it alive in C#, so I can't answer your question fully, though. If a started timer is treated as having an external reference, then that alone would keep both the timer and callback alive.
No. You don't need to stash away your timer. It would normally be garbage collected, since it is only referenced by your delegate. However, I believe that the Timer constructor places a reference with the underlying runtime, so you should be fine.
Raymond Chen probably has something to say in his blog post: The implementation of anonymous methods in C# and its consequences (part 1)
Your Timer variable t will stay accessible as long as there is a reference to your anonymous method. Your anonymous method will stay referenced until the event has fired. At least that long.
According to Raymond Chen, the c# compiler turns your code into something else, with the context of your method (including the this pointer of the enclosing object) all wrapped up in its own little compiler generated class. So it seems the anonymous method (or delegate) itself contains the reference to the timer.
Oh, and everyone else in this thread are correct: I just blurted out some stuff (and learned about how the C# compiler handles anonymous methods at the same time).
So yes, you have a circular reference. But I'm pretty sure creating a timer should hook that up somewhere in the runtime / windows. Let's have a check.
Using Reflector, you can follow the trail from System.Timer.Timer() through to TimerBase, which has an extern method AddTimerNative. I'm not sure how to peek into that, but I'm going to bet it registers your timer with the OS.
Conclusion: Your timer will not go out of scope, as it will be referenced by the OS until it fires.

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