У меня есть приложение .NET, для которого требуется использовать WebBrowser
, чтобы автоматически перемещаться по нескольким страницам. Но если я зайду, например, в Google и настрою Google Instant on, а затем что-то пробую и перемещаюсь вручную через следующую кнопку несколько раз, память, используемая моим приложением, начнет увеличиваться.
Проблема может заключаться в том, что Google Instant каким-то образом сохраняет данные с предыдущих страниц, но даже после того, как я перемещаюсь в другом месте, например "около: пусто", используемая память не будет уменьшаться. Эта проблема также возникает с 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 с помощью 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)
) и не исправил его. Память опустилась на диспетчер задач, но это видно только. Приложение перестало отвечать на запросы после того, как многие браузерные навигации потребовались, чтобы перестать отвечать на запросы, не вызывая эту функцию.