Small Memory Leak - c#

New to threading, delegates, and garbage collection.
I have a C# program in Visual Studio 2013 that runs a loop on background thread to constantly update controls on a form in my main thread. While the loop is running (and only when the loop is running), Performance Monitor shows a small but steady increase in Private Bytes for that program.
When the background thread is stopped and joined, there is no decrease in the Private Bytes usage but it no longer increases. This program needs to run a long time with the looping thread so a small leak could become a problem after hours / days.
I can comment out the lines in the loop where it calls for the update method; this successfully curbs the issue. What am I doing to prevent garbage collection in that method?
P.S.: If you point me to a program for looking through the heap, please give me a step-by-step on how to install and use it. I've been a little burned out lately and what I've seen online so far isn't obvious enough for my brain at the moment.
private IAsyncResult iar; // Store the IAsyncResult to check for completion the next time I call it.
public delegate void Assisted_UpdateTimer(int totalSeconds, int secondsElapsed, int secondsRemaining);
public void UpdateTimer(int totalSeconds, int secondsElapsed, int secondsRemaining)
{
if (this.InvokeRequired || pbTimeBar.InvokeRequired) // If we need to be threadsafe
{
if (iar != null) // If we've invoked something before
{
if (iar.IsCompleted) // If the last thing we invoked has completed
{
this.EndInvoke(iar);
Assisted_UpdateTimer _delegate = new Assisted_UpdateTimer(UpdateTimer);
iar = this.BeginInvoke(_delegate, totalSeconds, secondsElapsed, secondsRemaining);
}
}
else // Invoke for the first time
{
Assisted_UpdateTimer _delegate = new Assisted_UpdateTimer(UpdateTimer);
iar = this.BeginInvoke(_delegate, totalSeconds, secondsElapsed, secondsRemaining);
}
}
else // The actual method code
{
TimeSpan timeElapsed = new TimeSpan(0, 0, secondsElapsed);
TimeSpan timeRemaining = new TimeSpan(0, 0, secondsRemaining);
int percent = (int)(((double)secondsElapsed / (double)totalSeconds) * 100);
if (pbTimeBar.Maximum != totalSeconds) pbTimeBar.Maximum = totalSeconds;
if (secondsElapsed >= 0) pbTimeBar.Value = secondsElapsed; // pbTimeBar is a progress bar
// Add text to progress bar
pbTimeBar.CreateGraphics().DrawString(percent + "%", new Font("Arial", (float)8.25, FontStyle.Regular), new SolidBrush(Color.FromArgb(255, 0, 0, 0)), new PointF(pbTimeBar.Width / 2 - 10, pbTimeBar.Height / 2 - 7));
labElapsed.Text = string.Format("{0:00}:{1:00}:{2:00} Elapsed", timeElapsed.Hours, timeElapsed.Minutes, timeElapsed.Seconds);
labRemaining.Text = string.Format("Remaining {0:00}:{1:00}:{2:00}", timeRemaining.Hours, timeRemaining.Minutes, timeRemaining.Seconds);
trayIcon.Text = string.Format("Toast Timer\nRemaining: {0:00}:{1:00}:{2:00}\nElapsed: {3}%", timeRemaining.Hours, timeRemaining.Minutes, timeRemaining.Seconds, percent);
}
}

I haven't checked your full code but the memory leak could be a possible output of strong delegate reference. You see, when you attach a delegate to the event of an object, the object will never be garbage collected unless the delegate reference is removed manually. Here is a documentation reference from msdn to help you understand the scenario better and with possible solutions -
http://msdn.microsoft.com/en-us/library/aa970850(v=vs.110).aspx
Listening for events can lead to memory leaks. The typical technique for listening to an event is to use the language-specific syntax that attaches a handler to an event on a source. For example, in C#, that syntax is: source.SomeEvent += new SomeEventHandler(MyEventHandler).
And for the last part of your question - I usually use Ant Profiler for memory testing. It is not free but the trial version usually works and gives you enough time to solve the issue.
http://www.red-gate.com/products/dotnet-development/ants-performance-profiler/
http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/
Comment: I am guessing repeating call to UpdateTimer could make a possible memory leak if it is attaching new delegates in each call.

Related

Assigning a value to Label.Text eventually results in StackOverflowException

I am building a dashboard style Windowsform, I have various timers to update the controls on the form, and all are working great, except one, the only one I am using a Label Control as the indicator.
I have various System.Timers to update the data of the indicators all stored in classes that run ever 5 minutes or so, then another timer set to update the GUI that runs every second. For some reason this code:
l_LastShipment.Text = GlobalStatic.fulfillmentInd.Caption;
within the GUI Update eventually errors in a StackOverflowException, usually after a couple of hours. fulfillmentInd.Caption is just a string variable in the class, and at the time of the error contains the proper data (Usually "0:01" or something similar).
Originally the GUI Timer was a System.Timer but was afraid the Invoke to update the Label was were the error was coming from, so switched the GUI timer to a Windows.Forms.Timer so it didn't require the Invoke, yet the error still occurs.
There is no recursion taking place, and I even monitored the time it takes the Update GUI function to run and it is always less than 1/10th of a second, even when the error occurs.
Here is the trimmed GUI Refresh function:
private void guiHandleTimer(object sender, EventArgs e)
{
//Refresh the Indicators
//Stopwatch
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//Compact indicator
if (GlobalStatic.compactInd.Changed())
{
pb_Compact.Value = GlobalStatic.compactInd.value;
pb_Compact.Caption = GlobalStatic.compactInd.Caption;
pb_CompactTT.SetToolTip(pb_Compact, GlobalStatic.compactInd.tooltip);
GlobalStatic.compactInd.Reset();
}
//
//Other Indicators removed for readability
//
//Fulfillment Indicator
if (GlobalStatic.fulfillmentInd.Changed())
{
if (GlobalStatic.fulfillmentInd.value <= 59)
{
//Within an Hour, Light Yellow
p_fulfillment.BackColor = Color.LightYellow;
}
else if (GlobalStatic.fulfillmentInd.value <= 300)
{
//Between an hour and 5 hours, Change to Green
p_fulfillment.BackColor = Color.Green;
}
else
{
//Over 5 hours old, Grey
p_fulfillment.BackColor = Color.LightGray;
}
l_LastShipment.Text = GlobalStatic.fulfillmentInd.Caption; <-------This is the line that generates the StackOverflow ----->
ToolTip test = new ToolTip();
test.SetToolTip(p_fulfillment, GlobalStatic.fulfillmentInd.tooltip);
test.SetToolTip(l_LastShipment, GlobalStatic.fulfillmentInd.tooltip);
GlobalStatic.fulfillmentInd.Reset();
}
stopwatch.Stop();
TimeSpan t = stopwatch.Elapsed;
if(TimeSpan.Compare(largestTime,t)==-1)
{
//largestTime is shorter than t, change largestTime
largestTime = t;
}
T_GUI.Text = largestTime.ToString(#"hh\:mm\:ss\:fff");
}
Here is the Timer Setup, called during Form Load, the only place that GUIHandleTimer is mentioned in code:
//GUI Refresh Timer
System.Windows.Forms.Timer guiTimer = new System.Windows.Forms.Timer();
guiTimer.Interval = 1000;
guiTimer.Tick += new EventHandler(guiHandleTimer);
I solved the StackOverflow. The reason it took so long for me to figure it out and finally to ask here, is that Visual Studio was always code-breaking on the Label.Text line highlighted in my original question. Unfortunately, that was not the line causing the StackOverflow, it was the next line that was causing it.
ToolTip test = new ToolTip();
For some reason I didn't move that New ToolTip() out of the Handler after I was done fixing my ToolTips, so I was overloading new ToolTips into the Stack every second. Moving that line out of the function fixed the error.
The weird thing is that wasn't where Visual Studio was marking the StackOverflow error, causing much pain in attempting to resolve it.

WPF how to effectively detect user activity

I have an application in which I have to logout after say x seconds of inactivity.
I therefore have a timer going on and calculating a timespan from the last user acitivity resetted with:
dtLastActivity = DateTime.Now;
So the problem is that I don't think it's the best approach to associate EVERY single event in my program with the afore mentioned code.
But in the end I don't need EVERY event: all what is useful is to track KEYPRESS and MOUSEUP.
Would it be correct to track those two event in the MainWindow?
I have to admit that I still have not put into practice this (but I will) for I am not sure that this is the best approach for the purpose in the title.
Being new to WPF I am also not clear if tracking keyboard and mouse in the mainwindow shall not affect the behaviour in the children (that are the controls that effectively are the target of the event).
Thank you in advance for any help.
---EDIT---
The proposed solutions are very elegant. Particularly this one:
public static class IdleTimeDetector
{
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public static IdleTimeInfo GetIdleTimeInfo()
{
int systemUptime = Environment.TickCount,
lastInputTicks = 0,
idleTicks = 0;
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
lastInputInfo.dwTime = 0;
if (GetLastInputInfo(ref lastInputInfo))
{
lastInputTicks = (int)lastInputInfo.dwTime;
idleTicks = systemUptime - lastInputTicks;
}
return new IdleTimeInfo
{
LastInputTime = DateTime.Now.AddMilliseconds(-1 * idleTicks),
IdleTime = new TimeSpan(0, 0, 0, 0, idleTicks),
SystemUptimeMilliseconds = systemUptime,
};
}
}
but it is too automatic. I have no control over it.
E.g. if I use it from the beginning it gets idle BEFORE starting because my application has a quite long start time with splash screen, deserialization etc...
The solution proposed by Fruchtzwerg is much more similar to my needs because I get complete control over it. It has also the advantage that if I click on another application the timer is not resetted!!
I usually use the approach described by you. I running a timer and restart every interaction. The events of a window are:
PreviewMouseDown="Window_Action"
PreviewKeyDown="Window_Action"
Restarting the timer:
private void Window_Action(object Sender, InputEventArgs e)
{
IdleTimer.Stop();
IdleTimer.Start();
}
Never had any prolmems with this soultion. Restarting the timer takes under 80 ticks with a stopwatch. So the resources are in my opinion no problem.
Also you can specify the userinteractions by adding terms in your event.
The Preview-Events are not disturbing other events. This tunneling-behavoiur is described here.

Kill my application while it's using a threaded dll call

I have a structural problem resulting in an System.ObjectDisposedException with a dll.
More specifically it's a µEye Camera driver that is advised to capture data from a camera. I got two events from this camera that are fired asynchronously:
OnFrameEvent
OnSequenceEvent
The latter tells me that my capture is beeing completed and I can continue in saving my images.
This is the code that does the work:
private void onSequenceEvent(object sender, EventArgs e)
{
uEye.Camera Camera = sender as uEye.Camera;
SequenceCount++;
Camera.Acquisition.Stop();
int s32SeqID;
statusRet = Camera.Memory.Sequence.GetLast(out s32SeqID);
Invoke((MethodInvoker)delegate ()
{
lblStatus.Text = "Save Images...";
this.pbCapture.Value = 0;
});
Rectangle src = new Rectangle();
Rectangle dst = new Rectangle();
src.X = AOI_Size.X;
src.Y = AOI_Size.Y;
src.Width = AOI_Size.Width;
src.Height = AOI_Size.Height;
dst.X = 0; dst.Y = 0; dst.Width = AOI_Size.Width; dst.Height = AOI_Size.Height;
Bitmap bitmap_source = new Bitmap(MySensorInfo.MaxSize.Width, MySensorInfo.MaxSize.Height);;
Bitmap bitmap_destination = new Bitmap(dst.Width, dst.Height);;
Graphics g = Graphics.FromImage(bitmap_destination);
for (int i = 1; i < s32SeqID; i++)
{
Camera.Memory.ToBitmap(i, out bitmap_source);
g.DrawImage(bitmap_source, dst, src, GraphicsUnit.Pixel);
bitmap_destination.Save(PathToSave + i.ToString() + ".bmp");
this?.Invoke((MethodInvoker)delegate ()
{
pbOverallProgress.Value++;
pbCapture.Value++;
});
}
bitmap_source.Dispose();
g.Dispose();
this.CloseForm?.Invoke(1);
}
However - as you may expect the Invoke call will cause the ObjectDisposedException as the "Cancel"-Button is beeing pressed:
this?.Invoke((MethodInvoker)delegate ()
{
pbOverallProgress.Value++;
pbCapture.Value++;
});
Here's the code of the Cancel-Button:
private void btn_Exit_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Do you really want to cancel?", "Abort", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
this.CloseForm?.Invoke(0);
}
}
private void UEye_Dialog_Form_CloseForm(int exitCode)
{
this?.Invoke((MethodInvoker)delegate ()
{
if (Camera != null)
{
Camera.EventFrame -= onFrameEvent;
Camera.EventSequence -= onSequenceEvent;
}
Camera?.Acquisition.Stop();
Camera = null;
ReturnCode = exitCode;
this.Close();
});
}
UEye_Dialog_Form_CloseForm(int exitCode) is a event where CloseForm is it's delegate.
I hope this was not too much information :)
This exception only occure if the image is beeing saved, not if I'm waiting for the sequence to be captured.
Sure I could pack the UI Update code within a try-catch-block or check if the forms state is Disposed/Disposing. But for my little programming skills it looks like a structural problem.
Thank you for your help :)
The tricky part is that you're doing multi-threading without synchronization.
Invoke presents one such synchronization point, which is fine. However, as you've found out, it doesn't work after the handle is disposed - this makes perfect sense; Invoke simply sends a window message to the given handle, and when the handle no longer exists there's noöne to deal with the message (not to mention what would Close (which just sends WM_CLOSE etc.) do when the window no longer exists).
Solving this is quite tricky, actually. Even if you check if the form is disposed before trying the Invoke, it might still be disposed between the check and the Invoke itself. locking would allow you to handle the synchronization, but you'd need to lock in DestroyHandle or perhaps an event like Closing - the key is to make sure that whatever signal you send is safely tied to whether Invoke is safe right now. Of course, you don't really want to use Invoke - you need BeginInvoke, otherwise you're guaranteed to have a deadlock when Invoke needs to wait for the UI thread which is currently waiting for the lock to be released. Not good :)
Being prepared for an ObjectDisposedException might be the best solution. But looking through the reference source code, it doesn't look like it's 100% correct either - it's consistent on a single thread, but you're not calling Invoke on the UI thread (obviously).

C# real time chart desktop application too slow

I am taking over a C# code from someone who implemented a desktop application to read real time data from the Serial Port and displaying it in charts (using the Chart Class).
The code seems to be working, but is very slow. It seems to be updating the chart around once in 4 seconds (0.25Hz). However, I can see that it is multi-threaded and has no delay commands, so I don't understand why it is running so slow. Could the updating of charts slow it down? Ideally I would like to achieve 1000 data points per second (1kHz), displaying it in real time and saving it to the hard disk, where the size of each data point is about 30 bytes.
I spent few days understanding the code, but it's too cumbersome to follow, all written in a single file, with no comments. Is my goal of reading 1000 data points per second realistic/achievable?
I'm also considering to re-write the code (as opposed to trying to fix it), considering it's only about 2,500 lines long. Any tips would be appreciated. Also, if I rewrite the code, what language might be better for this application?
I developed some code where I got significant performance improvement, it may work for you. Here is what I did-
Step 1: I would first identify, which one is the bottle neck, drawing/rendering of the chart
or serial port
Step 2: If you find its the rendering-- then add this in your form/chart setup, it will draw much faster. But first double check to make sure you're not in remote desktop mode.
<!-- language: c# -->
// No double buffering for remote, only local
public bool OptimizeOfLocalFormsOnly(System.Windows.Forms.Control chartControlForm)
{
if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
{
SetUpDoubleBuffer(chartControlForm);
return true;
}
return false;
}
public static void SetUpDoubleBuffer(System.Windows.Forms.Control chartControlForm)
{
System.Reflection.PropertyInfo formProp =
typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
formProp.SetValue(chartControlForm, true, null);
}
I assume you using winform application :
Use serialPort component :
Configure its properties : (BaudRate, DataBits, StopBits, Parity ...)
Make use of its event (DataReceived) to collect your inputs.
You can send commands in a loop and collect the inputs/drawing them on chart component roughly like :
while(/*some condition*/)
{
serialPort.Write(/* your command */);
// you have to think of response time
// so implement something that waits a bit before calling the port again
// I would do it using timers
int tick= Environment.TickCount;
while(Environment.TickCount - tick <= 100) // wait 100 milliseconds
{
Application.DoEvents();
}
}
// collect the data as:
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// use according to your needs, for example
string data = "";
int readByte;
int available;
available = serialPort.BytesToRead;
if(available >= 30) // 30 bytes as stated in your question
{
for(int i=0; i<30; i++)
{
readByte = serialPort.ReadByte();
data += String.Format("{0:2X}", readByte);
}
// you can call some methods to save/display your collected data from here
save_to_file(data);
display_to_chart(data);
}
}
I developed a similar app where I was displaying 16charts * 256 samples/sec. Storing the data in a buffer and creating a separate thread for updating the charts worked for me.
When new data is read, data is stored in a list or array. Since it is real-time data, the timestamps are also generated here. Using the sample rate of the data acquired: timeStamp = timeStamp + sampleIdx/sampleRate;
public void OnDataRead(object source, EEGEventArgs e)
{
if ((e.rawData.Length > 0) && (!_shouldStop))
{
lock (_bufferRawData)
{
for (int sampleIdx = 0; sampleIdx < e.rawData.Length; sampleIdx++)
{
// Append data
_bufferRawData.Add(e.rawData[sampleIdx]);
// Calculate corresponding timestamp
secondsToAdd = (float) sampleIdx/e.sampleRate;
// Append corresponding timestamp
_bufferXValues.Add( e.timeStamp.AddSeconds(secondsToAdd));
}
}
Then, create a thread that sleeps every N ms (100ms is suitable for me for a 2 seconds display of data, but if I wanna display 10 seconds, I need to increase to 500ms of sleep time for the thread)
//Create thread
//define a thread to add values into chart
ThreadStart addDataThreadObj = new ThreadStart(AddDataThreadLoop);
_addDataRunner = new Thread(addDataThreadObj);
addDataDel += new AddDataDelegate(AddData);
//Start thread
_addDataRunner.Start();
And finally, update the charts and make the thread sleep every N ms
private void AddDataThreadLoop()
{
while (!_shouldStop)
{
chChannels[1].Invoke(addDataDel);
// Sleeep thread for 100ms
Thread.Sleep(100);
}
}
The AddData method, simply reads the X (timestamp) and Y values stored in the buffer and add its to the charts using ptSeries.Points.AddXY(xValue, yValue)

GC contains lots of pinned objects after a while

I have a strange phenomenon while continuously instantiating a com-wrapper and then letting the GC collect it (not forced).
I'm testing this on .net cf on WinCE x86. Monitoring the performance with .net Compact framework remote monitor. Native memory is tracked with Windows CE Remote performance monitor from the platform builder toolkit.
During the first 1000 created instances every counter in perfmon seems ok:
GC heap goes up and down but the average remains the same
Pinned objects is 0
native memory keeps the same average
...
However, after those 1000 (approximately) the Pinned object counter goes up and never goes down in count ever again. The memory usage stays the same however.
I don't know what conclusion to pull from this information... Is this a bug in the counters, is this a bug in my software?
[EDIT]
I do notice that the Pinned objects counter starts to go up as soon the total bytes in use after GC stabilises as does the Objects not moved by compactor counter.
The graphic of the counters http://files.stormenet.be/gc_pinnedobj.jpg
[/EDIT]
Here's the involved code:
private void pButton6_Click(object sender, EventArgs e) {
if (_running) {
_running = false;
return;
}
_loopcount = 0;
_running = true;
Thread d = new Thread(new ThreadStart(LoopRun));
d.Start();
}
private void LoopRun() {
while (_running) {
CreateInstances();
_loopcount++;
RefreshLabel();
}
}
void CreateInstances() {
List<Ppb.Drawing.Image> list = new List<Ppb.Drawing.Image>();
for (int i = 0; i < 10; i++) {
Ppb.Drawing.Image g = resourcesObj.someBitmap;
list.Add(g);
}
}
The Image object contains an AlphaImage:
public sealed class AlphaImage : IDisposable {
IImage _image;
Size _size;
IntPtr _bufferPtr;
public static AlphaImage CreateFromBuffer(byte[] buffer, long size) {
AlphaImage instance = new AlphaImage();
IImage img;
instance._bufferPtr = Marshal.AllocHGlobal((int)size);
Marshal.Copy(buffer, 0, instance._bufferPtr, (int)size);
GetIImagingFactory().CreateImageFromBuffer(instance._bufferPtr, (uint)size, BufferDisposalFlag.BufferDisposalFlagGlobalFree, out img);
instance.SetImage(img);
return instance;
}
void SetImage(IImage image) {
_image = image;
ImageInfo imgInfo;
_image.GetImageInfo(out imgInfo);
_size = new Size((int)imgInfo.Width, (int)imgInfo.Height);
}
~AlphaImage() {
Dispose();
}
#region IDisposable Members
public void Dispose() {
Marshal.FinalReleaseComObject(_image);
}
}
Well, there's a bug in your code in that you're creating a lot of IDisposable instances and never calling Dispose on them. I'd hope that the finalizers would eventually kick in, but they shouldn't really be necessary. In your production code, do you dispose of everything appropriately - and if not, is there some reason why you can't?
If you put some logging in the AlphaImage finalizer (detecting AppDomain unloading and application shutdown and not logging in those cases!) does it show the finalizer being called?
EDIT: One potential problem which probably isn't biting you, but may be worth fixing anyway - if the call to CreateImageFromBuffer fails for whatever reason, you still own the memory created by AllocHGlobal, and that will currently be leaked. I suspect that's not the problem or it would be blowing up more spectacularly, but it's worth thinking about.
I doubt it's a bug in RPM. What we don't have here is any insight into the Ppb.Drawing stuff. The place I see for a potential problem is the GetIImagingFactory call. What does it do? It's probably just a singleton getter, but it's something I'd chase.
I also see an AllochHGlobal, but nowhere do I see that allocation getting freed. For now that's where I'd focus.

Categories

Resources