C# UserControl timer continues to tick after parent MFC CDialog destroyed [duplicate] - c#

Preface: I know how to solve the problem. I want to know why it arises. Please read the question from top to bottom.
As we all (should) know, adding event handlers can cause memory leaks in C#. See Why and How to avoid Event Handler memory leaks?
On the other hand, objects often have similar or connected life cycles and deregistering event handlers is not necessary. Consider this example:
using System;
public class A
{
private readonly B b;
public A(B b)
{
this.b = b;
b.BEvent += b_BEvent;
}
private void b_BEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler AEvent;
}
public class B
{
private readonly A a;
public B()
{
a = new A(this);
a.AEvent += a_AEvent;
}
private void a_AEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler BEvent;
}
internal class Program
{
private static void Main(string[] args)
{
B b = new B();
WeakReference weakReference = new WeakReference(b);
b = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool stillAlive = weakReference.IsAlive; // == false
}
}
A and B reference each other implicitly via events, yet the GC can delete them (because it's not using reference counting, but mark-and-sweep).
But now consider this similar example:
using System;
using System.Timers;
public class C
{
private readonly Timer timer;
public C()
{
timer = new Timer(1000);
timer.Elapsed += timer_Elapsed;
timer.Start(); // (*)
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// NoOp
}
}
internal class Program
{
private static void Main(string[] args)
{
C c = new C();
WeakReference weakReference = new WeakReference(c);
c = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool stillAlive = weakReference.IsAlive; // == true !
}
}
Why can the GC not delete the C object? Why does the Timer keep the object alive? Is the timer kept alive by some "hidden" reference of the timer mechanics (e.g. a static reference)?
(*) NB: If the timer is only created, not started, the issue does not occur. If it's started and later stopped, but the event handler is not deregistered, the issue persists.

The timer logic relies on an OS functionality. It is actually the OS that fires the event. OS in turn uses CPU interrupts to implement that.
The OS API, aka Win32, does not hold references to any objects of any kind. It holds memory addresses of functions which it has to call when a timer event happens. .NET GC has no way to track such "references". As a result a timer object could be collected without unsubscribing from the low-level event. It is a problem because OS would try to call it anyway and would crash with some weird memory access exception. That's why .NET Framework holds all such timer objects in the statically referenced object and removes them from that collection only when you unsubscribe.
If you look at the root of your object using SOS.dll you will get the next picture:
!GCRoot 022d23fc
HandleTable:
001813fc (pinned handle)
-> 032d1010 System.Object[]
-> 022d2528 System.Threading.TimerQueue
-> 022d249c System.Threading.TimerQueueTimer
-> 022d2440 System.Threading.TimerCallback
-> 022d2408 System.Timers.Timer
-> 022d2460 System.Timers.ElapsedEventHandler
-> 022d23fc TimerTest.C
Then if you look at the System.Threading.TimerQueue class in something like dotPeek, you will see that it is implemented as a singleton and it holds a collection of timers.
That's how it works. Unfortunately the MSDN documentation is not crystal clear about it. They just assumed that if it implements IDisposable then you should dispose it no question asked.

Is the timer kept alive by some "hidden" reference of the timer mechanics (e.g. a static reference)?
Yes. It is built in the CLR, you can see a trace of it when you use the Reference Source or a decompiler, the private "cookie" field in the Timer class. It is passed as the second argument to the System.Threading.Timer constructor that actually implements the timer, the "state" object.
The CLR keeps a list of enabled system timers and adds a reference to the state object to ensure it doesn't get garbage collected. Which in turn ensures that the Timer object doesn't get garbage collected as long as it is in the list.
So getting a System.Timers.Timer garbage collected requires that you call its Stop() method or set its Enabled property to false, same thing. Which cause the CLR to remove the system timer from the list of active timers. Which also removes the reference to the state object. Which then makes the timer object eligible for collection.
Clearly this is desirable behavior, you do not typically want to have a timer just disappear and stop ticking while it is active. Which will happen when you use a System.Threading.Timer, it stops calling its callback if you don't keep a reference to it, either explicitly or by using the state object.

I think this is related to the way that the Timer is implemented. When you call Timer.Start(), it sets Timer.Enabled = true. Look at the implementation of Timer.Enabled:
public bool Enabled
{
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
get
{
return this.enabled;
}
set
{
if (base.DesignMode)
{
this.delayedEnable = value;
this.enabled = value;
}
else if (this.initializing)
{
this.delayedEnable = value;
}
else if (this.enabled != value)
{
if (!value)
{
if (this.timer != null)
{
this.cookie = null;
this.timer.Dispose();
this.timer = null;
}
this.enabled = value;
}
else
{
this.enabled = value;
if (this.timer == null)
{
if (this.disposed)
{
throw new ObjectDisposedException(base.GetType().Name);
}
int dueTime = (int) Math.Ceiling(this.interval);
this.cookie = new object();
this.timer = new Timer(this.callback, this.cookie, dueTime, this.autoReset ? dueTime : 0xffffffff);
}
else
{
this.UpdateTimer();
}
}
}
}
}
It looks like a new timer is created, with a cookie object passed to it (very odd!). Following that call path leads to some other complex code involving creating a TimerHolder and a TimerQueueTimer. I expect at some point a reference held outside the Timer itself is created, until such time as you call Timer.Stop() or Timer.Enabled = false.
This isn't a definitive answer, since none of the code I posted creates such a reference; but it's complicated enough down in the guts to lead me to suspect that something like that is happening.
If you have Reflector (or similar) have a look and you'll see what I mean. :)

Because Timer is still active. (Event handler is not removed for Timer.Elapsed).
If you want to properly dispose, Implement IDisposable interface, remove the event handler in the Dispose method, and use the using block or call the Dispose manually. The issue will not occur.
Example
public class C : IDisposable
{
...
void Dispose()
{
timer.Elapsed -= timer_elapsed;
}
}
And then
C c = new C();
WeakReference weakReference = new WeakReference(c);
c.Dispose();
c = null;

I think the problem arises from this line;
c = null;
In general, most developers think that making an object equal to null results in object to be deleted by garbage collector. But this is not the case; in fact only a reference to a memory location (where c object is created) is deleted; if there are any other references to the related memory location, object will not be marked for deletion. In this case, since Timer is referencing the related memory location, object will not be deleted by garbage collector.

Let's first talk about Threading.Timer. Internally, the timer will construct a TimerQueueTimer object using callback and state passed to Timer ctor (say new Threading.Timer(callback, state, xxx, xxx). The TimerQueueTimer will be added to a static list.
If callback method and state have no "this" info (say using static method for callback and null for state), then the Timer object can be GCed when no reference.
On the other hand, if a member method is used for callback, the delegate containing "this" will be stored in the static list mentioned above. So Timer object cannot be GCed since the "C" (in your example) object is still referenced.
Now let's back to System.Timers.Timer which internally wraps Threading.Timer. Note that when the former constructs the latter, a System.Timers.Timer member method is used, so System.Timers.Timer object cannot be GCed.

Related

Timers and Garbage Collection

Say I have a class like this
class A
{
private B _objB
private Timer _timer; // Using System.Timers
public A(objB)
{
_objB = objB;
_timer = new Timer();
_timer.Interval = 1000;
_timer.Elapsed += SomeEvent;
}
public void Begin()
{
_timer.start();
}
public void End()
{
_timer.Dispose();
}
public void SomeEvent (object sender, ElapsedEventArgs e)
{
if (_objB.Condition())
{
// do something
}
else
{
_timer.Dispose();
}
}
}
Now somewhere else in my code in a different class I do this
public void SomeMethod(B objectB)
{
A objA = new A(objectB);
objA.Begin();
// do other stuff
// objA.End() can be called here but for this example it's not
}
I know that when I exit the scope of SomeMethod(), objA will won't be garbage collected because there is a timer event that keeps on firing. What I'm not sure about are the following:
1) When in SomeEvent, I hit the else condition and call _timer.Dispose(), this stops firing further events, but will this tell the GC that it can clean up the timer, and objA? In another words, am I causing any memory leaks?
2) Are there any race conditions that can cause exceptions? So like if I'm calling _timer.Dispose() and somehow have another timer event in queue, does entering that event causes any exceptions?
I'm just unsure if I'm doing right amount of cleaning up to avoid memory leaks.
Generally correct. When you dispose Timer, ObjA will be eligible for GC. In fact, garbage collector will collect it during its next garbage collection cycle.
Keep in mind that, It will not collect your object immediately after it becomes eligible for GC. Garbage collector uses its heuristic algorithm to to trigger garbage collection. It occurs only when there is a memory pressure. In fact when Gen0 or Large Object Heap about to overflow.
Possibly.. Have a look at here.
Callbacks can occur after the Dispose() method overload has been
called, because the timer queues callbacks for execution by thread
pool threads. You can use the Dispose(WaitHandle) method overload to
wait until all callbacks have completed.

Can Timers get automatically garbage collected?

When you use a Timer or a Thread that will just run for the entire lifetime of the program do you need to keep a reference to them to prevent them from being garbage collected?
Please put aside the fact that the below program could have timer as a static variable in the class, this is just a toy example to show the issue.
public class Program
{
static void Main(string[] args)
{
CreateTimer();
Console.ReadLine();
}
private static void CreateTimer()
{
var program = new Program();
var timer = new Timer();
timer.Elapsed += program.TimerElapsed;
timer.Interval = 30000;
timer.AutoReset = false;
timer.Enabled = true;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
var timerCast = (Timer)sender;
Console.WriteLine("Timer fired at in thread {0}", GetCurrentThreadId());
timerCast.Enabled = true;
}
~Program()
{
Console.WriteLine("Program Finalized");
}
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
}
Could the timer get collected in that above example? I ran it for a while and I never got a exception nor a message saying ~Program() was called.
UPDATE: I found out from this question (thanks sethcran) that threads are tracked by the CLR, but I still would like an answer about Timers.
This is only a problem with the System.Threading.Timer class if you don't otherwise store a reference to it somewhere. It has several constructor overloads, the ones that take the state object are important. The CLR pays attention to that state object. As long as it is referenced somewhere, the CLR keeps the timer in its timer queue and the timer object won't get garbage collected. Most programmers will not use that state object, the MSDN article certainly doesn't explain its role.
System.Timers.Timer is a wrapper for the System.Threading.Timer class, making it easier to use. In particular, it will use that state object and keep a reference to it as long as the timer is enabled.
Note that in your case, the timer's Enabled property is false when it enters your Elapsed event handler because you have AutoReset = false. So the timer is eligible for collection as soon as it enters your event handler. But you stay out of trouble by referencing the sender argument, required to set Enabled back to true. Which makes the jitter report the reference so you don't have a problem.
Do be careful with the Elapsed event handler. Any exception thrown inside that method will be swallowed without a diagnostic. Which also means that you won't set Enabled back to true. You must use try/catch to do something reasonable. If you are not going to intentionally end your program, at a minimum you'll need to let your main program know that something isn't working anymore. Putting Enabled = true in a finally clause can avoid getting the timer garbage collected, but at the risk of having your program throw exceptions over and over again.
Let's carry out an experiment:
private static void UnderTest() {
// Timer is a local varibale; its callback is local as well
System.Threading.Timer timer = new System.Threading.Timer(
(s) => { MessageBox.Show("Timer!"); },
null,
1000,
1000);
}
...
// Let's perform Garbage Colelction manually:
// we don't want any surprises
// (e.g. system starting collection in the middle of UnderTest() execution)
GC.Collect(2, GCCollectionMode.Forced);
UnderTest();
// To delay garbage collection
// Thread.Sleep(1500);
// To perform Garbage Collection
// GC.Collect(2, GCCollectionMode.Forced);
So far
if we keep commented both Thread.Sleep(1500); and GC.Collect(2, GCCollectionMode.Forced); we'll see message boxes appear: the timer is working
if we uncomment GC.Collect(2, GCCollectionMode.Forced); we'll see nothing: the timer starts then it is collected
if we uncomment both Thread.Sleep(1500); and GC.Collect(2, GCCollectionMode.Forced); we'll see a single message box: the timer starts, goes off a single message box and then the timer is collected
So System.Threading.Timers are collected as any other object instances.
Add this code to a program and run it. You'll see that the timer is NOT collected.
private void DoStuff()
{
CreateTimer();
Console.WriteLine("Timer started");
int count = 0;
for (int x = 0; x < 1000000; ++x)
{
string s = new string("just trying to exercise the garbage collector".Reverse().ToArray());
count += s.Length;
}
Console.WriteLine(count);
Console.Write("Press Enter when done:");
Console.ReadLine();
}
private void Ticktock(object s, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("Ticktock");
}
private void CreateTimer()
{
System.Timers.Timer t = new System.Timers.Timer(); // Timer(Ticktock, null, 1000, 1000);
t.Elapsed += Ticktock;
t.Interval = 1000;
t.AutoReset = true;
t.Enabled = true;
}
So the answer to your question appears to be that the timer is not eligible for collection and will not be collected if you don't maintain a reference to it.
It's interesting to note that if you run the same test with System.Threading.Timer, you'll find that the timer is collected.

Dispose or kill DispatcherTimer object and Accessing DispatcherTimer object

Question 1:
Hi, I would like to know is there a way by which I can dispose or kill the object of DispatcherTimer and create a new object of same name?
Question 2:
Can I access the DispatcherTimer object in some other class if it is set to Public?
You cannot dispose DispatcherTimer object. It doesn't implement IDisposable interface. You cannot explicit kill (free, destroy) objects in managed world.
If you don't need the timer object any more, disable it and set reference to it to null. It will be collected later by GC.
You can disable or stop the timer by setting IsEnabled = false or call timer.Stop(). The effect is the same.
Yes. I suppose you have public property like this:
public DispatcherTimer MyTimer { get; private set; }
Adding to a correct answer from Lubo (and bringing up this topic from comments under it): even though you cannot dispose DispatcherTimer (most probably, because it's wired up to unmanaged part of the WPF / UWP Dispatcher itself which lives as long as the app itself), you still should unsubscribe from its events.
Say, if you had some method (StartRefreshTimer) where you initialized your DispatcherTimer and started listening to its Tick event:
private DispatcherTimer _refreshTimer = new DispatcherTimer() { Interval = TimeSpan.FromMinutes(1) };
private void StartRefreshTimer()
{
if (_refreshTimer != null)
{
_refreshTimer.Tick += OnTick; // subscribe to timer's ticks
_refreshTimer.Start(); // start timer
}
}
private void OnTick(object sender, object args)
{
// your custom OnTick logic
}
Then you should have a method which stops the timer and unsubscribes from its events:
private void StopRefreshTimer()
{
if (_refreshTimer != null)
{
_refreshTimer.Stop(); // stop timer
_refreshTimer.Tick -= OnTick; // unsubscribe from timer's ticks
}
}
You should make sure you call this "tear down" method when your class goes out of scope (for example, when your WPF / UWP control or ViewModel is unloaded). If you don't unsubscribe from timer events you could end up with memory leaks caused by references from outer scope to your timer hosting class.

How to start an object containing a timer in a new thread?

How to start running an object containing a timer in a new thread?
I have the below code that I should probably change it:
class MemoryCleaner : IDisposable
{
private readonly static MemoryCleaner Instance = new MemoryCleaner();
private readonly Timer _memoryWatcher = new Timer(15 * 1000);
public Timer MemoryWatcher
{
get
{
return this._memoryWatcher;
}
}
public void Dispose()
{
_memoryWatcher.Elapsed -= memoryWatcher_Elapsed;
this._memoryWatcher.Stop();
}
private void memoryWatcher_Elapsed(object sender, ElapsedEventArgs e)
{
var currentProcess = Process.GetCurrentProcess();
var megaBytes = currentProcess.PrivateMemorySize64 / (1024 * 1024);
if (megaBytes > 100)
{
// force an immediate garbage collection to free some unused memory quickly; this is an expensive process!
GC.Collect();
}
}
internal static void Start()
{
// this should be created in a new thread
Instance.MemoryWatcher.Elapsed += Instance.memoryWatcher_Elapsed;
Instance.MemoryWatcher.Start();
GC.KeepAlive(Instance);
}
internal static void Stop()
{
Instance.Dispose();
}
}
I'd like to use it like:
MemoryCleaner.Start();
// my memory thirsty code which generates so much garbage, e.g. downloads a document then disposes it.
MemoryCleaner.Stop();
What it should do is that I should create a new thread then on that thread it should create a new instance of the MemoryCleaner object and start that object.
How would that be possible to do that?
Some background info:
Basically, what the code should do is that it should checke the memory used by the main process every 15 seconds and forces the garbage collection if memory usage exceeds 100MB since so many garbage will be created.
Hope the question is clear.
Thanks,
If you're creating a System.Threading.Timer or System.Timers.Timer it doesn't much matter which thread you create it on - unless you specify a synchronization object, the timer will fire on a thread-pool thread anyway. Why would you want to create a thread just for the creation part?
(I'm not at all sure that all of this is a good idea anyway, but that's a separate matter... You should also consider whether making a singleton implementation implement IDisposable is really sensible.)

Correct use of using with Timer (or any object where using is relevant)

present code is currently structured as follows:
System.Timers.Timer myTimer;
public void FirstMethod() {
myTimer;= new System.Timers.Timer();
myTimer.start();
SecondMethod();
}
public void SecondMethod(){
//several things happen here and then
myTimer.stop();
}
I've been advised that I could use using to correctly garbage collect the Timer object. So I've tried to apply something like the following to my code (taken from here):
using (SomeClass someClass = new SomeClass())
{
someClass.DoSomething();
}
I assume the following will error because myTimer is not known by SecondMethod()?
public void FirstMethod() {
using (System.Timers.Timer myTimer = new System.Timers.Timer())
{
myTimer.start();
SecondMethod();
}
}
public void SecondMethod(){
//several things happen here and then
myTimer.stop();
}
You can only use using if the object should be disposed (=destroyed) after the using block ends. A timer usually lasts longer than that (as in your example).
You wrap an object that implements the IDisposable interface in a using block when it makes sense to do so. In this case it does not because the object must be valid at a higher scope. Remember, a using statement is just shorthand (syntactic sugar) for this:
var myDisposableObj = new Whatever();
try
{
// use myDisposableObj. If an exception is thrown
// in here somewhere the call to Dispose() still occurs.
}
finally
{
myDisposableObj.Dispose();
}
In your case you need to ensure that you call Dispose() on the object when you are done with it (and in a manner that accounts for exceptions which may be thrown that would prevent the call to Dispose() from taking place). You need the Timer to stick around for a while, so a using block is out of the question.
The "using pattern" is used to automatically call Dispose when the implementing object is no longer in scope. Dispose is used to clean up any unmanaged resources. Finalize is what the garbage collector calls before the object is "collected".
You could try to "force" collection, however -
"It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues."
So you need SecondMethod to have "access" to myTimer?
Yes, you are right. Your code is wrong because myTimer is declared as a local variable and it's only available in the using scope. You should change your code to sth. like this
public void FirstMethod() {
using (System.Timers.Timer myTimer = new System.Timers.Timer())
{
myTimer.start();
SecondMethod(myTimer);
}
}
public void SecondMethod(System.Timers.Timer theTimer){
//several things happen here and then
theTimer.stop();
}
using can only be used on an object that implements IDisposable and it will automatically be disposed at the end of the using block. If you need to use that object anywhere else, then you cannot use using.
In your example, not only will your original object not be known in other methods, but it'll be deleted.

Categories

Resources