DispatcherTimer keeps increasing memory usage until app crash - c#

I am currently writing an app that mainly makes use of a DispatcherTimer to emulate Stopwatch functionality. While my DispatcherTimer is running within the app, my app's memory usage goes up to 100MB in less than 10 minutes which is especially weird considering how simple the app's functionality is. This wouldn't have normally been a problem except for the fact that the app's rapid increase in memory usage then causes it to crash and close out. I have looked all over the web and repeatedly have come across articles acknowledging the existence of a DispatcherTimer memory leak, however all of the fixes to this memory leak consist of stopping the DispatcherTimer when it is no longer needed. My memory leak occurs while the DispatcherTimer is still needed, not when it is accidentally left running. I need to allow for users to keep their stopwatch running for however long they choose, so stopping the DispatcherTimer when it's not needed anymore doesn't do much for me. I have tried adding GC.Collect() at the end of my TimerTick event handler, however, that didn't seem to do much either.
public MainPage()
{
InitializeComponent();
PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Disabled;
Timer.Stop();
Timer.Interval = new TimeSpan(0, 0, 1);
Timer.Tick += new EventHandler(TimerTick);
Loaded += new System.Windows.RoutedEventHandler(MainPage_Loaded);
}
void TimerTick(object sender, EventArgs e)
{
timeSpan1 = DateTime.Now.Subtract(StartTimer);
timeSpan2 = DateTime.Now.Subtract(StartTimer2);
WatchHour.Text = timeSpan1.Hours.ToString();
WatchMinute.Text = timeSpan1.Minutes.ToString();
WatchSecond.Text = timeSpan1.Seconds.ToString();
SecondaryHour.Text = timeSpan2.Hours.ToString();
SecondaryMinute.Text = timeSpan2.Minutes.ToString();
SecondarySecond.Text = timeSpan2.Seconds.ToString();
if (WatchHour.Text.Length == 1) WatchHour.Text = "0" + WatchHour.Text;
if (WatchMinute.Text.Length == 1) WatchMinute.Text = "0" + WatchMinute.Text;
if (WatchSecond.Text.Length == 1) WatchSecond.Text = "0" + WatchSecond.Text;
if (SecondaryHour.Text.Length == 1) SecondaryHour.Text = "0" + SecondaryHour.Text;
if (SecondaryMinute.Text.Length == 1) SecondaryMinute.Text = "0" + SecondaryMinute.Text;
if (SecondarySecond.Text.Length == 1) SecondarySecond.Text = "0" + SecondarySecond.Text;
}
This is my TimerTick event handler and a bit of my MainPage constructor, the textboxes present in the event handler display the time elapsed from starting the stopwatch. Am I doing something specifically wrong here that is causing such a huge increase in memory? I had previously thought the issue was because the TextBoxes were somehow caching their previous contents by default coupled with rapid changes in text due to the stopwatch functionality, however, after completely removing the TextBoxes from my app and analyzing it, I am quite sure they aren't the problem. As stated above, adding GC.Collect() at the end of this TimerTick handler didn't do anything to decrease my memory usage. Does anyone have an idea of how I could reduce my memory usage with DispatcherTimer, maybe by somehow manipulating the GC function to actually work?
Thanks in advance!

Why are you declaring the timespan1 and timespan2 outside of the timer tick event? Does the memory look better if you create it inside of the event handler

Could you please try the following code snippet,
Step:1
Add the button and textblock in xaml first.
Step:2
Use the following namespaces:
using System.Diagnostics; // for Stopwatch API Access
Step:3 use the below mentioned code snippet:
public partial class WmDevStopWatch : PhoneApplicationPage
{
Stopwatch stopWatch = new Stopwatch();
DispatcherTimer oTimer = new DispatcherTimer();
public WmDevStopWatch()
{
InitializeComponent();
oTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
oTimer.Tick += new EventHandler(TimerTick);
}
void TimerTick(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(() =>
{
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
stopWatch.Elapsed.Hours, stopWatch.Elapsed.Minutes, stopWatch.Elapsed.Seconds,
stopWatch.Elapsed.Milliseconds / 10);
textBlock1.Text = elapsedTime;
});
}
private void button1_Click(object sender, RoutedEventArgs e)
{
stopWatch.Start();
oTimer.Start();
}
}
Hope it works for you.
Let me know your feedback for the same.

I have finally isolated the core of my memory leak, the issue was not with my DispatcherTimer but instead with my AdRotator Control. The problem has been identified on the side of the AdRotator developers and I am currently using a different Ad control until the problem is fixed.
Thank you all for your help, I really appreciate your time and effort!

Related

C# WinForms Trying to Update UI with Timer but without slowing the performance down

so currently I've got an application that has 2 processes. One process is pining, while pinging the process is writing down the results into an array.
Another process is for updating the UI every second with a timer. Whats being update is an mschart to be more exact.
That's how I have set up the timer:
readonly System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
myTimer.Interval = 1000;
myTimer.Tick += WriteFunction;
Now this is the method that I'm calling every second for refreshing the UI / actually Graph:
private void WriteFunction(object objectInfo, EventArgs e)
{
foreach (NetPinger.source.AddGraph b in graphList)
{
b.fileRead();
}
}
The method, for updating the chart is inside another class, and looks like this:
public void fileRead()
{
double unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
chart_holder.Series[0].Points.Clear();
for (double i = unixTimestamp; unixTimestamp - graphSizing < i; i--)
{
bool exists;
try
{
exists = Array.Exists(file, element => element.XValue == i);
exists = true;
}
catch
{
exists = false;
}
try
{
if (exists == false)
{
DataPoint point = new DataPoint(i, 0);
chart_holder.Series[0].Points.Add(point);
}
else
{
DataPoint point = Array.Find(file, element => element.XValue == i);
chart_holder.Series[0].Points.Add(point);
}
}
catch(Exception ex)
{
MessageBox.Show(Convert.ToString(ex));
}
}
}
Now what I noticed was that if the graphSizing (number that I'm looping through) is kept low, the performance is kinda fine and everything is sync (multiple graphs from UI are updated at same time etc.) like it should be. But as soon as i rise it let's say to like 50 or even 250 (what the goal should be) the UI and Graph updating are being very very slow. It's only updating like every 3s and the UI is in general very laggy and slow.
Does anyone has any advice how I can maintain good performance or where I messed up that the UI is so slow? For further questions or more details feel free to ask.
Thanks a lot for your time and helping.
Greetings C.User
Your code always runs in the UI thread, since System.Windows.Forms.Timer calls the delegate on the UI thread. Even if that where not the case (and you used System.Timer instead), you delegate everything back to the UI with your Invoke call. You need to make sure you prepare the data on another thread first and do as little as possible in the UI thread itself.

Timer Skipping ElapsedEvents

So I'm trying to run an event every 5 seconds. Seems to work using System.Timers.Timer to some extend but it seems to be skipping sometimes, not even responding late, just plain skipping it.
Anything I could do about this?
internal void DetermineScreenCapping()
{
System.Timers.Timer ScreenCapTimer = new System.Timers.Timer();
/// Initialize the screencapper (doesn't enable it yet)
// Tell the timer what top do when it elapses
ScreenCapTimer.Elapsed += new ElapsedEventHandler(ExecuteCode);
// Set it to go off every five seconds
ScreenCapTimer.Interval = 5000;
// And start it
ScreenCapTimer.Enabled = true;
}
private void ExecuteCode(object source, ElapsedEventArgs e)
{
if (IsCurrentlyWorking == true)
{
Execute Code
}
}
The problem indeed wasn't the timer not doing it's job. It was the code being executed that had some problems that couldn't even be seen debugging for some reason.
I changed the code and the timer works properly now ^^

Is this a memory leak or will garbage collection fix it

Lets say I have a button that gets clicked and it does this:
public void ButtonClick(object sender, EventArgs e)
{
System.Timers.Timer NewTimer = new System.Timers.Timer();
NewTimer.AutoReset = false;
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
}
If this button gets clicked 100 times what happens to those instances that have been created? Will garbage collection kick in or does the System.Timers.Timer.Close method need calling and if it does where do you call it from?
No this will not cause a memory leak. In fact the way your code is written it's not guaranteed to execute properly. Timers.Timer is really just a wrapper over Threading.Timer and it's explicitly listed as being collectable even if it's currently running.
http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
Here you keep no reference to it and hence the very next GC could collect it while your form is still running and before the event ever fires
EDIT
The documentation for Timers.Timer appears to be incorrect. The Timer instance will not be collected if it's unreferenced. It will indeed live on
var timer = new System.Timers.Timer
{
Interval = 400,
AutoReset = true
};
timer.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer.Enabled = true;
WeakReference weakTimer = new WeakReference(timer);
timer = null;
for (int i = 0; i < 100; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine("Weak Reference: {0}", weakTimer.Target);
Console.ReadKey();
They will be collected once method is left. TimerElapsed will be either called or not depending on when Timer gets finalized. Most likely it will be dead long before 1 second passed.
When you call Timer.Close() you thus call Timer.Dispose() that de-registers timer from timer queue and in that case TimerElapsed won't be called (of course if it was not called before).
If you leave timer not closed, GC will eventaully call Finalize() that in turn will call Dispose(). But there is not exact knowledge when it will happen :)
See below example, Console.Out.WriteLine("called!!!") will never execute:
using (System.Timers.Timer NewTimer = new System.Timers.Timer())
{
NewTimer.AutoReset = false;
ElapsedEventHandler TimerElapsed = (sender, args) => { Console.Out.WriteLine("called!!!"); };
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
Thread.Sleep(3000);
After answers by the_joric and JaredPar and running profiler tests which showed timers sticking around after garbage collection kicked in the reason they stuck around was because there is a reference to the event handler sticking around. For a more detailed explanation see this answer.
The real answer is that it is a memory leak unless the timer is closed in the elapsed event handler.
Just goes to show that although I trust the answers on SO (maybe too much) from the great contributors they may be slightly off.

Thread issue in C#

I am trying to generate a random fruit and display it on GUI in a label. I am using this code to do it.
partial class Form1 : Form
{
int MagicNumber = 0;
List<string> NameList = new List<string>();
Random r = new Random();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
NameList.Add("Apples");
NameList.Add("Pears");
NameList.Add("Oranges");
NameList.Add("Bananas");
NameList.Add("Kiwi");
for (int i = 0; i < 8; i++)
{
Thread t = new Thread(new ThreadStart(Display));
t.Start();
label1.Text = NameList[MagicNumber];
Thread.Sleep(1000);
}
}
private void Display()
{
MagicNumber = r.Next(5);
}
}
The problem is the fact that in GUI i see only the last result of fruits choice and not how they are skipped from an iteration to other. I thought that this code will give me the possibility to see how fruits changes until the last was chosen , when i is 8.
Please if you have an idea why this code is not displaying how the fruits are chosen in label give me a hand !
Thanks.
You seem to be confusing timers and threads. In this case, I think what you want is a timer; specifically, System.Windows.Forms.Timer. You might do something like this:
partial class Form1 : Form
{
Timer timer = new Timer();
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
timer.Tick += (s, e) =>
{
if (i < 8)
{
label1.Text = nameList[r.Next(5)];
i++;
}
else
timer.Stop();
};
timer.Interval = 1000;
timer.Start();
}
}
The idea is that you set a timer to tick once a second, and then each time it ticks, you change the label and increment the counter until it reaches 8 -- at which point it stops. You always want to make sure you call Start() after you've set Tick and Interval; otherwise, under some strange circumstances, the timer might tick before you have a chance to change the settings.
Alternatively, you could use threading and Sleep(), in which case it might look like this:
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(Display));
t.Start();
}
private void Display()
{
for(int i = 0; i < 8; i++)
{
label1.Text = NameList[r.Next(5)];
Thread.Sleep(1000);
}
}
Thread.Sleep() always sleeps the thread that it's called from -- so maybe this is what you meant to do.
However, this might throw a thread synchronization exception -- Forms prevents you from accessing UI controls from another thread, since it might be in an invalid state (i.e. in the middle of rendering or doing something else that's volatile). System.Windows.Forms.Timer actually runs on the UI thread, so it's easier to manage.
Your approach is flawed, but you may want to understand what is going on in your code, as it may help you find a better approach:
for (int i = 0; i < 8; i++)
{
Thread t = new Thread(new ThreadStart(Display));
t.Start();
label1.Text = NameList[MagicNumber];
Thread.Sleep(1000);
}
You are looking through, creating eight threads every time the button is clicked. Do you have a reason to create eight threads? If so, you may want to create them once, inside your init function and reuse them.
Then there is a race here in that your threads may not have had time to change MagicNumber before it is used, as the loop starts the threads then immediately changes the text, before going to sleep.
The sleep is another problem, as you haven't gotten off of the main (event) thread, so the text isn't changed until you exit that event handler.
If you want to see the text changing, then you will need to get off of the main thread, and in a second thread go through and do the loop of eight.
Then, you can put that thread to sleep, and since the main thread was free to make the change you will see it.
Here is an article from MS that is a bit dated, but the basic idea should help you:
http://msdn.microsoft.com/en-us/magazine/cc188732.aspx
Now you can use lambda expressions for your threads, as shown here:
http://www.rvenables.com/2009/01/threading-tips-and-tricks/
Just call Application.DoEvents(); after assigning text to label - that will refresh UI.
BTW I don't understand why you are using threads to generate random numbers
The problem is that when you execute an event handler or a function called from it, the changes are rendered at the end. Try changhing the label text inside the thread where you get the random number. You also have to set the CheckForIllegalCrossThreadCalls property to false in the form constructor.
Your observed problem of the form not refreshing is due to your function blocking the GUI thread and preventing a redraw of the window while its running. And it's continuously running for 8 seconds. The GUI thread needs to handle messages to allow a window to be redrawn.
But apart from what you observed it has has at least two theoretical problems related to threading:
The read of MagicNumber isn't volatile, so the compiler may read it only once and cache the result. It probably won't do that in practice since the code between each reading of the variable is so complicated that it can't guarantee that they won't affect the variable.
r.Next isn't threadsafe. So calling it from two different threads at the same time can corrupt the Random instance. Won't happen in practice either since the delay is so long that one thread will most likely have finished before the next one starts.
There is a much better way to choose a random item:
label1.Text = NameList.OrderBy(f => Guid.NewGuid()).First();
Randomizing on different threads is a bad idea in of itself.

Timer, event and garbage collection : am I missing something?

Consider the following code :
class TestTimerGC : Form
{
public TestTimerGC()
{
Button btnGC = new Button();
btnGC.Text = "GC";
btnGC.Click += (sender, e) => GC.Collect();
this.Controls.Add(btnGC);
System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
tmr.Interval = 1000;
tmr.Tick += (sender, e) => this.Text = DateTime.Now.ToString();
tmr.Start();
}
}
If I'm not mistaken, after the tmr variable goes out of scope, the Timer isn't referenced anywhere, so it should be eligible for garbage collection. But when I click the GC button, the timer continues to run, so I guess it wasn't collected...
Does anyone have an explanation for that ?
PS: it's not a real program of course, I was just trying to prove a point to someone... but my proof didn't work ;)
OK, I think I know what's going on... I looked at the code of the Timer class with Reflector, and I found the following instruction in the setter of the Enabled property :
this.timerRoot = GCHandle.Alloc(this);
So, when it is started, the timer allocates a GCHandle for itself, which prevents its collection by the GC...

Categories

Resources