Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
283 views
in Technique[技术] by (71.8m points)

.net - 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...