WPF DispatcherTimer Memory Issue - c#

Edit: If useful, this project is on GitHub at https://github.com/lostchopstik/BetterBlync
I am building an application for the Blync status light using their provided API. This application polls the Lync/Skype for Biz client and converts the status to the appropriate light color. All aspects thus far work as expected, however when I leave this program running for an extended period of time, the memory usage grows until a System.OutOfMemory exception occurs.
I have narrowed the problem down to the DispatcherTimer holding the timer in memory and preventing it from being GCed. After reading some things online I found you could manually call for garbage collection, but this is bad practice. Regardless, here is what I have in my code right now:
private void initTimer()
{
timer = new DispatcherTimer();
timer.Interval = new TimeSpan( 0, 0, 0, 0, 200 );
timer.Tick += new EventHandler( Timer_Tick );
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
// Check to see if any new lights are connected
blync.FindBlyncLights();
// Get current status from Lync client
lync.GetStatus();
// Change to new color
setStatusLight();
if ( count++ == 100 )
{
count = 0;
GC.Collect();
}
}
The timer ticks every 200ms. I commented out all methods inside the timer and just let it run empty, and it still burned memory.
I am wondering what the proper way to handle this timer is. I've used the DispatcherTimer in the past and not had this issue.
I would also be open to trying something besides the DispatcherTimer.
If it is also useful, I have been messing with MemProfiler and here as my current graph with manual GC:
http://imgur.com/Iut91mF

It's a little hard to tell without seeing the rest of the code or the class the timer belongs to. I don't see anywhere you call Stop() on the timer. Does it need to be stopped?
You could also keep a local reference to the timer in whatever class you're in and call Start() and Stop() as needed.
If the timer never needs to be stopped and runs indefinitely, I would certainly look at what you're allocating as the timer runs and that's probably where your issue is.

Related

How can I execute a code in C# (Windows Service) periodically in the most precise way?

I have a code with which I am reading in 35ms intervals the current and position values of a machine's CNC axis from a remote computer.
The data is read from the CNC/PLC control system of the machine
My C# code has to run on our company server with Windows Server 2019. I am sending the data to Kafka, our AI experts have to interpret the current and position curve shapes for an AI algorithm. So the data has to be read every 35 ms as precise as possible
Normally I have used first a system timer with a 35ms period. It seems to work but I am not sure if this is the best way. Is there a more precise method than using a system timer?
My code
public void Main()
{
InitializeTimer_1();
}
public void InitializeTimer_1()
{
System.Timers.Timer timer1 = new System.Timers.Timer();
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent1);
timer1.Interval = 35;
timer1.Enabled = true;
}
public void OnTimedEvent1(object sender, EventArgs e)
{
// my Data reading code
}
There are multiple ways to solve this problem.
It first depends on what kind of application you have.
If you have a console app then you can schedule it to run every 35ms using the windows task scheduler and it will work.
If it is a long-running process like windows service then you can use the same code you have
There is one very useful library hangfire, you can explore this as well.
Also, refer to this post as well, you may get more directions.
Edit: System.Timers.Timer is sufficient for most the purpose, you could also consider System.Threading.Timer for short intervals, it allows more precise timings but its will run on a separate thread so keep that in mind. There is one more option System.Diagnostics.Stopwatch which has more high precision than other approaches.
The actual precision of the timer also depends on hardware, OS and the workload on the machine.
Now you can evaluate all the approaches and chose the best one for you.
The timer accepts a direct callback method. If you want to execute something periodic, it can be done as follows:
var timer = new Timer(TimerCallback, state, startAfterTimeSpan, repeatTimeSpan);
Where you can e.g. write a method
private void TimerCallback(object state)
{
// do something
}

How to keep reusing timer

I'm making a simple game on console for practice that requires a time limit each round and I've encountered a problem with trying to make it so I can use timer more than once. I have this:
class Program
{
static Timer timer = new Timer(1000);
static int t = 10;
static void Main(string[] args)
{
timer.Elapsed += Timer_Elapsed1;
timer.Start();
Console.ReadLine();
t = 10;
timer.Start();
Console.ReadLine();
}
My thoughts were that the 2nd timer.Start() would get the same result as the first, but nothing happens.
private static void Timer_Elapsed1(object sender, ElapsedEventArgs e)
{
t--;
Console.WriteLine("Hello!");
if (t == 0)
{
Console.WriteLine("Goodbye!");
timer.Stop();
}
}
Why is the second timer.Start() not doing anything? How do I make it so I can use timer.Start() again and it will do the same thing as the first time? I'm using System.Timers
NVM IT DOES WORK, IM JUST DUMB LOL
Try stopping or disabling the first timer before trying to start a second time.
C# - how do you stop a timer?
I fell compelled to give you some disclaimers:
First, console is not the right Environment for Game Development. Neither is any of the GUI techs. For games you got XNA (pretty dated) and with .NET Core a bunch of new Options. The important thing is that you have a Game Loop of some form. Or at least imitate one.
Secondly, I am unsure how well most Timers work in console apps. Most of them use callbacks wich usually require a MessageQueue - wich is a GUI feature. I guess you could try a Multithreading time, but then you have to relearn everything if you leave Console applications.
As for your code: I am unsure when the Timer tick happens since you specified no interval. But I guess either:
never
after the 2nd timer start

Remove and reset Static Object

I am working on an app that has a static countdown running. It needs to be static since the object itself needs to be accessed from different classes.
But after redoing this bit of code for a while:
timer.Stop();
timer.Dispose();
timer.Enabled = false;
timer = new System.Timers.Timer();
timer.Interval = 10;
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
My app becomes extremely slow. I believe that maybe I am not disposing the timer object right and therefore creating many objects in the ram. Evneutally, after many times of this code, the app fails.
Am I disposing the object right before setting it up again (with the new keyword)? Or am I missing something vital?
Thank you!
It is:
public static System.Timers.Timer timer;
Well the reason why this is static, is because in my activity in my app there is also a recyler view integrated. And when I click on an item in my recycler view i need to manipulate the timer from outside the recycler view but inside the activity as well. If the timer is not public static I would have to intstantiate another object of that timer but this is not affecting the currently running timer. So maybe I got this all wrong? Is there a third option? Thank you!
In these kinds of scenarios, your best bet is to reuse the existing timer rather than dispose old ones and create new ones. This saves you having to worry about unsubscribing event handlers etc.
I suspect you want to Stop and Start it instead.

C# System.Timers.Timer - Please, how do I make it stop?

I've got a Timer that's doing a 60 second countdown. When the ticks hit 60 seconds, it stops and disposes - no problem (I think). This is run in the context of a WebApi service. I need to be able to cancel the countdown from a UI, so I've exposed a method to handle this. Since the controller is transient (thanks Luaan) and, as Daniel points out, the app pool is not predictable, I need a way to send a "cancellable" countdown to clients. Ideas anyone?
[HttpGet]
public IHttpActionResult CancelCountdown()
{
// DOES NOTHING BECAUSE THERE'S A NEW INSTANCE OF THE CONTROLLER
timer.Stop();
timer.Dispose();
return Ok();
}
private void StartCountdown()
{
// MAY BE A BAD SOLUTION BECAUSE THE APP POOL MAY RECYCLE
timer.Interval = _timeIntervalInMilliseconds;
timer.Elapsed += BroadcastToClients;
timer.Start();
}
private void BroadcastToClients(object sender, EventArgs e)
{
_elapsed += 1;
if (_elapsed == _duration)//_duration is 60
{
timer.Stop();
timer.Dispose();
return;
}
_messageHub.Clients.All.shutdown(_elapsed);
}
It's kind of hard to provide an adequate solution without knowing what you're trying to accomplish with this, but i'll give it a shot.
As Luaan pointed out, controllers are designed to be essentially stateless, so you shouldn't put instance variable on them except for it's external dependencies, since each request creates a new instance of the controller class.
You could store the timer on a static dictionary, indexed by a GUID, and return the GUID on your controller and use it as the cancellation token.
Something like:
private static Dictionary<string,Timer> timers = new Dictionary<Guid,Timer>();
public Guid StartCountdown()
{
// MAY BE A BAD SOLUTION BECAUSE THE APP POOL MAY RECYCLE
timer.Interval = _timeIntervalInMilliseconds;
timer.Elapsed += BroadcastToClients;
var guid = Guid.NewGuid().ToString();
timers.Add(guid,timer);
timer.Start();
return guid;
}
public IHttpActionResult CancelCountdown(Guid cancelationToken)
{
//If the timer no longer exist or the user supplied a wrong token
if(!timers.HasKey(cancelationToken)) return;
var timer = timers[cancelationToken];
timer.Stop();
timer.Dispose();
timers.Remove(cancelationToken);
}
However this won't solve the problem with the AppPool recycling. For a more robust solution, instead of using a timer, you could store the start date and time of each countdown in a more permanent storage (say an SQL database, a NoSQL databse, a redis server or whatever), and have a running thread or global timer, or something like Hangfire, initialized on startup, that constantly checks your countdown storage. If enough time has passed to send a broadcast message you send it, and mark the countdown as finished. If a user wants to cancel the countdown, the controller will simply read the appropiate record, mark it as cancelled, and your running thread can ignore it.
If you go with this approach, you'll need to take into account some considerations:
If the timer interval is set too short you could have a perfomance bottleneck for having to access a permament storage too often. If the interval is too long, the countdown won't be too precise.
To alleviate this problem you could store the countdowns start time in permanent storage, in case the app pool resets and you need to restore them. And also have them stored in memory on a static variable for quicker access.
Please note that if you're working with a server farm instead of a single server, static variables won't be shared across instances.

.NET Windows Service with timer stops responding

I have a windows service written in c#. It has a timer inside, which fires some functions on a regular basis. So the skeleton of my service:
public partial class ArchiveService : ServiceBase
{
Timer tickTack;
int interval = 10;
...
protected override void OnStart(string[] args)
{
tickTack = new Timer(1000 * interval);
tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
tickTack.Start();
}
protected override void OnStop()
{
tickTack.Stop();
}
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
...
}
}
It works for some time (like 10-15 days) then it stops. I mean the service shows as running, but it does not do anything. I make some logging and the problem can be the timer, because after the interval it does not call the tickTack_Elapsed function.
I was thinking about rewrite it without a timer, using an endless loop, which stops the processing for the amount of time I set up. This is also not an elegant solution and I think it can have some side effects regarding memory.
The Timer is used from the System.Timers namespace, the environment is Windows 2003. I used this approach in two different services on different servers, but both is producing this behavior (this is why I thought that it is somehow connected to my code or the framework itself).
Does somebody experienced this behavior? What can be wrong?
Edit:
I edited both services. One got a nice try-catch everywhere and more logging. The second got a timer-recreation on a regular basis. None of them stopped since them, so if this situation remains for another week, I will close this question. Thank you for everyone so far.
Edit:
I close this question because nothing happened. I mean I made some changes, but those changes are not really relevant in this matter and both services are running without any problem since then. Please mark it as "Closed for not relevant anymore".
unhandled exceptions in timers are swallowed, and they silently kill the timer
wrap the body of your timer code in a try-catch block
I have seen this before with both timer, and looped services. Usually the case is that an exception is caught that stops the timer or looping thread, but does not restart it as part of the exception recovery.
To your other points...
I dont think that there is anything "elegant" about the timer. For me its more straight forward to see a looping operation in code than timer methods. But Elegance is subjective.
Memory issue? Not if you write it properly. Maybe a processor burden if your Thread.Sleep() isn't set right.
http://support.microsoft.com/kb/842793
This is a known bug that has resurfaced in the Framework more than once.
The best known work-around: don't use timers. I've rendered this bug ineffective by doing a silly "while (true)" loop.
Your mileage may vary, so verify with your combination of OS/Framework bits.
Like many respondents have pointed out exceptions are swallowed by timer. In my windows services I use System.Threading.Timer. It has Change(...) method which allows you to start/stop that timer. Possible place for exception could be reentrancy problem - in case when tickTack_Elapsed executes longer than timer period. Usually I write timer loop like this:
void TimeLoop(object arg)
{
stopTimer();
//Do some stuff
startTimer();
}
You could also lock(...) your main loop to protect against reentrancy.
Interesting issue. If it is truly just time related (i.e. not an exception), then I wonder if you can simply periodically recycle the timer - i.e.
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
CheckForRecycle();
// ... actual code
}
private void CheckForRecycle()
{
lock(someLock) {
if(++tickCount > MAX_TICKS) {
tickCount = 0;
tickTack.Stop();
// re-create timer
tickTack = new Timer(...);
tickTack.Elapsed += ...
tickTack.Start();
}
}
}
You could probably merge chunks of this with the OnStart / OnStop etc to reduce duplication.
Have you checked the error logs? Maybe you run out of timers somehow. Maybe you can create just one timer when you initialize the ArchiveService and skip the OnStart stuff.
I have made exactly the same as you in a few projects but have not had the problem.
Do you have code in the tickTac_Elapsed that can be causing this? Like a loop that never ends or some error that stops the timer, using threads and waiting for ending of those and so on?

Categories