Как обойти утечку памяти в элементе управления .NET Webbrowser?.net


Answers

Я взял код udione (он работал для меня, спасибо!) И изменил две мелочи:

  1. IKeyboardInputSite - это открытый интерфейс и имеет метод Unregister () , поэтому нам не нужно использовать отражение после того, как мы получили ссылку на коллекцию * _keyboardInputSinkChildren *.

  2. Поскольку представление не всегда имеет прямую ссылку на его класс окна (особенно в MVVM), я добавил метод GetWindowElement (DependencyObject element), который возвращает требуемую ссылку, пройдя через визуальное дерево.

Спасибо, udione

public void Dispose()
{
    _browser.Dispose();

    var window = GetWindowElement(_browser);

    if (window == null)
        return;

    var field = typeof(Window).GetField("_swh", BindingFlags.NonPublic | BindingFlags.Instance);

    var valueSwh = field.GetValue(window);
    var valueSourceWindow = valueSwh.GetType().GetField("_sourceWindow", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(valueSwh);
    var valuekeyboardInput = valueSourceWindow.GetType().GetField("_keyboardInputSinkChildren", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(valueSourceWindow);

    var inputSites = valuekeyboardInput as IEnumerable<IKeyboardInputSite>;

    if (inputSites == null)
        return;

    var currentSite = inputSites.FirstOrDefault(s => ReferenceEquals(s.Sink, _browser));

    if (currentSite != null)
        currentSite.Unregister();
}

private static Window GetWindowElement(DependencyObject element)
{
    while (element != null && !(element is Window))
    {
        element = VisualTreeHelper.GetParent(element);
    }

    return element as Window;
}

Спасибо вам всем!

Question

Это широко известная старая проблема с элементом управления .NET Webbrowser.

Резюме: наличие элемента управления веб-браузером .NET. Переход на страницу увеличивает использование памяти, которая никогда не освобождается.

Воспроизведите утечку памяти: добавьте элемент управления WebBrowser в форму. Используйте его для перехода на любые страницы, которые вы хотите. о: пустые работы, прокрутка на Картах Google до тех пор, пока ваше использование не станет 100 Мбайт +, а затем просмотр в другом месте, чтобы заметить, что только что освобожденная память является более драматичной демонстрацией.

Мои текущие требования к приложению включают запуск его в течение длительных периодов времени, отображение ограниченного окна браузера IE7. Запуск IE7 сам по себе с некоторыми ублюдками настройки крючков, BHOs ​​и групповые политики также не желательны, хотя это выглядит как резерв в это время. Внедрение браузера в приложение Windows Forms. Использование другой базы браузеров не является доступным вариантом для меня. Требуется IE7.

Предыдущие темы и статьи, относящиеся к этой известной утечке памяти:

Часто предлагаемые исправления, которые НЕ РАБОТАЮТ:

  • Переход на разные страницы не имеет значения. about: blank запускает утечку. Это не требует, чтобы страница имела javascript или любую другую дополнительную технологию.
  • Использование разных версий Internet Explorer не имеет значения. 7, 8 и 9 имеют одинаковые симптомы, и, насколько я слышал, все версии имеют такую ​​же утечку памяти в элементе управления.
  • Dispose () управление не помогает.
  • Сбор мусора не помогает. (На самом деле, исследования, которые я сделал в этом, указывают на то, что утечка находится в неуправляемом COM-коде, который управляет Webbrowswer.)
  • Минимизация и настройка доступной памяти процесса до -1, -1 (SetProcessWorkingSetSize () или simimlar.) Только уменьшает использование физической памяти, не влияет на виртуальную память.
  • Вызов WebBrowser.Stop () не является решением и нарушает функциональность для использования чего-либо, кроме статических веб-страниц, не делая больше, чем просто минимизирует утечку.
  • Принуждение к загрузке документа полностью, прежде чем переходить на другой также не поможет.
  • Загрузка элемента управления в отдельный appDomain не устраняет проблему. (Я не делал этого сам, но исследования показывают, что другие не добились успеха в этом маршруте.)
  • Использование другой оболочки, такой как csexwb2, не помогает, так как это также страдает от одной и той же проблемы.
  • Очистка кеша временных интернет-файлов ничего не делает. Проблема в активной памяти, а не на диске.

Память очищается, когда все приложение закрывается и перезапускается.

Я готов напрямую написать собственный контроль браузера в COM или Windows API, если это окончательное решение проблемы. Конечно, я бы предпочел менее сложное решение; Я бы предпочел не спускаться на более низкие уровни, чтобы что-то делать, потому что я не хочу изобретать колесо с точки зрения поддерживаемых функций браузера. Letalone дублирует функции IE7 и нестандартное поведение в браузере с рулонами.

Помогите?




После того, как я столкнулся с этой проблемой « Исходя из памяти» с разных сторон ( интерфейсы Win32 WorkSet / COM SHDocVw и т. Д. ) WebBrowser компонентом WPF WebBrowser , я обнаружил, что проблема для нас была в том, что плагин jqGrid, удерживающий на неуправляемых ресурсах в IE ActiveXHost и не освобождающий их после вызов WebBrowser.Dispose() . Эта проблема часто создается Javascript, который не ведет себя правильно. Странно, что Javascript отлично работает в обычном IE - просто не изнутри WebBrowser управления WebBrowser . Я предполагаю, что сбор мусора отличается между двумя точками интеграции, поскольку IE никогда не может быть действительно закрыт.

Одна вещь, которую я предлагаю, если вы создаете исходные страницы, - это удалить все компоненты JS и медленно добавлять их обратно. После того, как вы идентифицируете нарушающий JS-плагин ( как и мы ), должно быть легко устранить проблему. В нашем случае мы просто использовали $("#jqgrid").jqGrid('GridDestroy') чтобы правильно удалить события и связанные с ними элементы DOM. Это позаботилось об этой проблеме, вызвав ее, когда браузер закрыт через WebBrowser.InvokeScript .

Если у вас нет возможности изменять исходные страницы, на которые вы переходите, вам нужно будет добавить несколько JS на страницу, чтобы очистить события и элементы DOM, которые вызывают утечку памяти. Было бы неплохо, если бы Microsoft нашла разрешение на это, но пока мы остаемся исследовать плагины JS, которые нуждаются в очистке .




Я думаю, что этот вопрос давно остался без ответа. Так много потоков с тем же вопросом, но не с окончательным ответом.

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

step1: Создайте новую форму say form2 и добавьте в нее элемент управления веб-браузером. step2: В форме1, где у вас есть элемент управления веб-браузером, просто удалите его. step3: Теперь перейдите в Form2 и сделайте модификатор доступа для этого элемента управления веб-браузером общедоступным, чтобы его можно было получить в Form1 step4: создать панель в форме1 и создать объект формы2 и добавить его в панель. Form2 frm = new Form2 (); frm.TopLevel = false; frm.Show (); panel1.Controls.Add (FRM); step5: Вызвать код ниже с регулярными интервалами frm.Controls.Remove (frm.webBrowser1); frm.Dispose ();

Это оно. Теперь, когда вы запустите его, вы можете увидеть, что управление веб-браузером загружено, и оно будет установлено через равные промежутки времени, и больше не будет висит приложение.

Вы можете добавить приведенный ниже код, чтобы сделать его более эффективным.

        IntPtr pHandle = GetCurrentProcess();
        SetProcessWorkingSetSize(pHandle, -1, -1);


        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();



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

System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
try
{
     loProcess.MaxWorkingSet = (IntPtr)((int)loProcess.MaxWorkingSet - 1);
     loProcess.MinWorkingSet = (IntPtr)((int)loProcess.MinWorkingSet - 1);
}
catch (System.Exception)
{

     loProcess.MaxWorkingSet = (IntPtr)((int)1413120);
     loProcess.MinWorkingSet = (IntPtr)((int)204800);
}