Проблема памяти WebBrowser - PullRequest
7 голосов
/ 27 мая 2011

У меня есть приложение .NET, которому нужно использовать WebBrowser для автоматической навигации по множеству страниц.Но если я зайду, например, в Google и включу Google Instant, а затем выполню поиск чего-либо и несколько раз вручную перейду к следующей кнопке, объем памяти, используемой моим приложением, начнет увеличиваться.

Возможно, проблема заключается в следующем.что Google Instant каким-то образом хранит данные с предыдущих страниц, но даже после перехода в другое место, например, «about: blank», используемая память не уменьшается.Эта проблема также возникает в IE 9. Я начал записывать свою память, использованную на странице 60, и вот что я получил (в IE 9):

Page 60: 180 MB
Page 70: 214 MB
Page 80: 245 MB
Page 90: 280 MB

Итак, как вы можете видеть, память увеличивается почти линейнона 30 - 35 МБ каждые 10 страниц.Это не будет проблемой, если память будет освобождена после того, как я уйду из Google.Но это не так.

Я также пытался это и ничего не делал.

Редактировать: Я создал проект только для проверки этого.Вот мой Form1 код:

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);
            }
        }
    }
}

Что я делаю, так это поиск в Google с Google Instant, включившим на , а затем нажмите startButton (который вызывает startButton_Click).Приблизительно после 80 страниц я нажимаю stopButton, затем перехожу к «about: blank», затем возвращаюсь к Google и ищу что-нибудь еще и снова нажимаю startButton.

Сначала я проверил это на своем ПК с оперативной памятью 6 ГБ.Когда я достиг 1,5 ГБ, приложение перестало отвечать, но я не получил исключение OutOfMemory.Затем я проверил его на виртуальной машине с Windows 7 и 1 ГБ оперативной памяти.Когда он достиг примерно 300 МБ, веб-браузер в моем приложении перестал отвечать на запросы.

Если я нажму кнопку freeMem, которая вызывает freeMemButton_Click, память снова откроется (но см. Мой Edit2).Так что это "решает" мою проблему.Но теперь мой вопрос: зачем мне звонить SetProcessWorkingSetSize?Разве Windows не должна автоматически освобождать память?Кроме того, я не уверен, что вызов этой функции будет иметь какой-либо побочный эффект.

Я уверен, что это ошибка.Должен ли я пойти дальше и сообщить об этом?

Edit2: Я проверил решение Стефана (вызов SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1)) и не исправил его.Память у менеджера задач опустилась, но это только очевидно.Приложение перестало отвечать на запросы после того, как многие браузеры перестали отвечать на запросы, когда не вызывали эту функцию.

Ответы [ 3 ]

3 голосов
/ 25 июня 2011

Windows на самом деле не возвращает освобожденную память, если для этого нет причин.И единственная причина будет в том, что другой памяти требуется эта память, а другой памяти больше нет.Вот почему выглядит, как будто использование памяти увеличивается.

Попробуйте вызвать

SetProcessWorkingSetSize (GetCurrentProcess (), -1, -1);

иногда - это заставит ОС возвращать всю освобожденную память обратно в ОС.

0 голосов
/ 05 июля 2011

при работе с Webbrowser я обнаружил, что важно дождаться события «documentcompleted» и проверить, «завершено ли состояние», не переходя по следующей странице.В противном случае отмените навигацию и подождите снова, пока документ завершен (прервано) перед навигацией ....

может быть то, что использование таймеров и не проверка состояния веб-браузера могут быть проблемой

Следующее, что связано с Webbrowser-Control, это то, что вы не можете использовать его в многопоточности / Backgroundworker, так как для этого требуется STA .... (часто возникают проблемы с неотвечающим приложением)

решение для "ful-contol"(разбирая веб-сайты) с помощью .NET для меня, я должен был использовать WebRequest / Webresponse, вы можете снова преобразовать результат этого в Webbroswer.Document, если хотите, чтобы DOM выполнялся автоматически, используйте многопоточность, легко устанавливайте тайм-ауты / проксикоторый мне показался более удобным, чем использование Webbrowser-control.

Тем не менее я успешно реализовал анализ страниц Webbrowser-Control в другом проекте, используя подсказки отсюда ( Как исправить утечку памяти в IE WebBrowser Control? )

еще один "забавный" тонкий с Winforms-программированием явыяснилось, что кажется, что GC.Collect запускается, когда окно свернуто и вновь открыто -> уменьшает ли это использование памяти?(возможно, пост Стефана также ссылается на этот вопрос)

0 голосов
/ 26 июня 2011

Я думаю, что HtmlElement pnext не выпущен, так как это ComObject, и может быть ошибка в управлении браузером.

Попробуйте pnext.Release или попробуйте Marshal.Release и получите экземпляр ComObject для освобождения.

...