WebBrowser memory problem
I have a .NET application that needs uses a WebBrowser
to automatically navigate through a bunch of pages. But if I go to, for instance, Google and set Google Instant on, and then search anything and navigate manually through the next button several times, the memory used by my application will start increasing.
The problem might be that Google Instant is somehow keeping data from previous pages, but even after I navigate somewhere else, such as "about:blank", the memory used won't decrease. This problem also occurs with IE 9. I started writing down my memory used at page 60 and this is what I got (with IE 9):
Page 60: 180 MB
Page 70: 214 MB
Page 80: 245 MB
Page 90: 280 MB
So as you can see, the memory increases almost lineally by 30 - 35 MB every 10 pages. This wouldn't be a problem if the memory would be released after I navigate away from Google. But is not.
I also tried this and didn't do anything.
Edit: I made a project just to test this. Here is my Form1
code:
namespace WebBrowserMemoryTest
{
public partial class Form1 : Form
{
private int _Pages;
public Form1()
{
InitializeComponent();
webBrowser1.Navigate("http://www.google.com");
}
private void startButton_Click(object sender, EventArgs e)
{
_Pages = 0;
timer1.Start();
}
private void stopButton_Click(object sender, EventArgs e)
{
timer1.Stop();
}
private void timer1_Tick(object sender, EventArgs e)
{
HtmlElement next = webBrowser1.Document.GetElementById("pnnext");
if (_Pages <= 90)
{
if (null != next)
{
string href = next.GetAttribute("href");
webBrowser1.Navigate(href);
_Pages++;
}
else
{
timer1.Stop();
MessageBox.Show("Next button not found");
}
}
else
{
timer1.Stop();
MessageBox.Show("Done");
}
}
private void goButton_Click(object sender, EventArgs e)
{
webBrowser1.Navigate(textBox1.Text);
}
private void freeMemButton_Click(object sender, EventArgs e)
{
MemoryManagement.FlushMemory();
}
}
public class MemoryManagement
{
[DllImport("kernel32.dll")]
public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
public static void FlushMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
}
}
}
What I do is search anything in Google with Google Instant turned on , and then press the startButton
(which invokes startButton_Click
). After about 80 pages I press the stopButton
, then navigate to "about:blank", then go back to Google and search anything else and press the startButton
again.
I first tested this on my PC, which has 6 GB ram. When I reached 1.5 GB the application stopped responding but I didn't get any OutOfMemory
exception. Then I tested it on a virtual machine with Windows 7 and 1 GB ram. When it reached about 300 MB the web browser in my application became unresponsive.
If I press the freeMem
button, which calls freeMemButton_Click
, the memory goes back down (but see my Edit2). So that "solves" my problem. But now my question is why do I need to call SetProcessWorkingSetSize
? Isn't it Windows supposed to free the memory automatically? Also, I'm not sure if calling that function will have any side effect.
I'm pretty sure this is a bug. Should I go ahead and report it?
Edit2: I tested Stefan's solution (calling SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1)
) and didn't fix it. The memory went down on the task manager, but this is only apparent. The application became unresponsive after as many browser navigations it took to become unresponsive when not calling that function.
Windows doesn't really return freed memory if there's nor reason for it. And the only reason would be if another app requires that memory and there's no other memory available anymore. That's why it looks as if the memory use increases.
Try calling
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
sometimes - this will force the OS to return all freed memory back to the OS.
I think HtmlElement pnext is not released, since it's ComObject, and there may be a bug in Browser Control.
Try pnext.Release or try Marshal.Release and get the instance of ComObject to release.
when working with Webbrowser, i found that it is important to wait for the "documentcompleted" event and check if the "state" is "completed" bevore navigating no next page. Else cancel navigation and wait again for document-completed state (aborted ) bevore navigating....
could be that the use of timers and not checking the Webbrowser's state could be a problem
the next thing with the Webbrowser-Control is, that you cannot use it in multithread / Backgroundworker since it requires to be STA....( often makes problems with unresponsive application )
the solution for "ful-contol" (parsing websites ) using .NET for me, was to use WebRequest / Webresponse , you can cast the result of that to Webbroswer.Document again if you want the DOM to be "auto" executed , use it multithreaded , easyly set timeouts / proxy wich i found more comfortable than using Webbrowser-control.
Nevertheless i sucessfully implemented a Webbrowser-Control parsing pages in another project using hints from here ( How to Fix the Memory Leak in IE WebBrowser Control?)
another "funny" thin with Winforms-programming i found out is, that it seems that a GC.Collect is triggered when the window is minimized an opened again - > does this decrease the mem-usage ? ( maybee Stefan's post also references to this issue )
链接地址: http://www.djcxy.com/p/7204.html上一篇: 安卓
下一篇: WebBrowser内存问题