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




4 Answers

Эта утечка, по-видимому, является утечкой в ​​неуправляемой памяти, поэтому ничто из того, что вы делаете в своем процессе, не будет исправлять эту память. С вашего поста я вижу, что вы попытались избежать утечки довольно широко и без успеха.

Я бы предложил другой подход, если это возможно. Создайте отдельное приложение, которое использует элемент управления веб-браузера и запускает его из вашего приложения. Используйте описанный here метод для внедрения вновь созданного приложения в ваше собственное существующее приложение. Общайтесь с этим приложением, используя удаленные WCF или .NET. Периодически перезагружайте дочерний процесс, чтобы не допустить его большого объема памяти.

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

профилирование освобождение

Это широко известная старая проблема с элементом управления .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 и нестандартное поведение в браузере с рулонами.

Помогите?




Существует способ очистить утечки памяти, используя отражение и удаление ссылок из частных полей на mainForm. Это нехорошее решение, но для отчаянных людей здесь есть код:

//dispose to clear most of the references
this.webbrowser.Dispose();
BindingOperations.ClearAllBindings(this.webbrowser);

//using reflection to remove one reference that was not removed with the dispose 
var field = typeof(System.Windows.Window).GetField("_swh", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

var valueSwh = field.GetValue(mainwindow);

var valueSourceWindow = valueSwh.GetType().GetField("_sourceWindow", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(valueSwh);

var valuekeyboardInput = valueSourceWindow.GetType().GetField("_keyboardInputSinkChildren", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(valueSourceWindow);

System.Collections.IList ilist = valuekeyboardInput as System.Collections.IList;

lock(ilist)
{
    for (int i = ilist.Count-1; i >= 0; i--)
    {
        var entry = ilist[i];
        var sinkObject = entry.GetType().GetField("_sink", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        if (object.ReferenceEquals(sinkObject.GetValue(entry), this.webbrowser.webBrowser))
        {
            ilist.Remove(entry);
        }
    }
} 



Решение ниже помогло мне:

Protected Sub disposeBrowers()
    If debug Then debugTrace()
    If Me.InvokeRequired Then
        Me.Invoke(New simple(AddressOf disposeBrowers))
    Else
        Dim webCliffNavigate As String = webCliff.Url.AbsoluteUri
        Me.DollarLogoutSub()
        If dollarLoggedIn Then
            Exit Sub
        End If

        'Dim webdollarNavigate As String = webDollar.Url.AbsoluteUri
        Me.splContainerMain.SuspendLayout()
        Me.splCliffDwellers.Panel2.Controls.Remove(webCliff)
        Me.splDollars.Panel2.Controls.Remove(webDollar)
        RemoveHandler webCliff.DocumentCompleted, AddressOf webCliff_DocumentCompleted
        RemoveHandler webDollar.DocumentCompleted, AddressOf webDollar_DocumentCompleted
        RemoveHandler webCliff.GotFocus, AddressOf setDisposeEvent
        RemoveHandler webCliff.LostFocus, AddressOf setDisposeEvent
        RemoveHandler webDollar.GotFocus, AddressOf setDisposeEvent
        RemoveHandler webDollar.LostFocus, AddressOf setDisposeEvent
        webCliff.Stop()
        webDollar.Stop()

        Dim tmpWeb As SHDocVw.WebBrowser = webCliff.ActiveXInstance
        System.Runtime.InteropServices.Marshal.ReleaseComObject(tmpWeb)
        webCliff.Dispose()

        tmpWeb = webDollar.ActiveXInstance
        System.Runtime.InteropServices.Marshal.ReleaseComObject(tmpWeb)
        webDollar.Dispose()
        tmpWeb = Nothing

        webCliff = Nothing
        webDollar = Nothing
        GC.AddMemoryPressure(50000)
        GC.Collect()
        GC.WaitForPendingFinalizers()
        GC.Collect()
        GC.WaitForFullGCComplete()
        GC.Collect()
        GC.RemoveMemoryPressure(50000)
        webCliff = New WebBrowser()
        webDollar = New WebBrowser()
        webCliff.CausesValidation = False
        webCliff.Dock = DockStyle.Fill
        webDollar.CausesValidation = webCliff.CausesValidation
        webDollar.Dock = webCliff.Dock
        webDollar.ScriptErrorsSuppressed = True
        webDollar.Visible = True
        webCliff.Visible = True
        Me.splCliffDwellers.Panel2.Controls.Add(webCliff)
        Me.splDollars.Panel2.Controls.Add(webDollar)
        Me.splContainerMain.ResumeLayout()

        'AddHandler webCliff.DocumentCompleted, AddressOf webCliff_DocumentCompleted
        'AddHandler webDollar.DocumentCompleted, AddressOf webDollar_DocumentCompleted
        'AddHandler webCliff.GotFocus, AddressOf setDisposeEvent
        'AddHandler webCliff.LostFocus, AddressOf setDisposeEvent
        'AddHandler webDollar.GotFocus, AddressOf setDisposeEvent
        'AddHandler webDollar.LostFocus, AddressOf setDisposeEvent

        webCliff.Navigate(webCliffNavigate)
        disposeOfBrowsers = Now.AddMinutes(20)
    End If
End Sub

Удачи, Лейла




Поверьте, это скорее проблема .NET Framework, а не управление веб-браузером. Привязка к навигационному событию браузера с помощью обработчика, который будет располагать браузер, а затем перейти к: blank будет хорошим обходным путем. Например:

private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
  var browser = (WebBrowser) _stackPanel.Children[_stackPanel.Children.Count - 1];
  _stackPanel.Children.RemoveAt(_stackPanel.Children.Count-1);

  NavigatedEventHandler dispose = null;
  dispose = (o, args) =>
  {
    browser.Navigated -= dispose;
    browser.Dispose();
  };
  browser.Navigated += dispose;
  browser.Navigate(new Uri("about:blank"));
}



Related

.net memory memory-leaks browser webbrowser-control