Утечка памяти при использовании элемента управления WPF WebBrowser в нескольких окнах - PullRequest
10 голосов
/ 15 января 2010

Я работаю над проектом, в котором используется элемент управления WPF WebBrowser (System.Windows.Controls.WebBrowser). Элемент веб-браузера в программе является одним из многих видов деятельности, в которые может участвовать пользователь, и открывается в отдельном окне. После того, как пользователь уходит от браузера, окно закрывается, и каждый раз, когда пользователь возвращается в браузер, создается новое окно. Мы заметили значительную утечку памяти / снижение производительности в нашей программе (использование достигло ~ 700 МБ от ~ 200 начальных) при постоянном использовании браузера. После того, как не удалось обнаружить какие-либо точки утечек ресурсов в нашем собственном коде, я решил определить, связана ли проблема с нашим собственным элементом управления WebBrowser или элементом управления WPF.

Я создал новый простой проект, состоящий только из MainWindow и WebWindow. Кнопка в главном окне запускает браузер, направленный на gmail (сайт, на котором мы обнаружили наибольшую проблему из немногих, которые мы исследовали) После закрытия этого окна не происходит освобождения ресурсов (без уменьшения размера виртуальной машины в диспетчере задач или в Process Explorer), и количество объектов GDI, с которыми обрабатывает процесс, не уменьшается (программа запускается с ~ 30, открытие браузера занимает до ~ 140 и после закрытия браузера ~ 140 все еще открыты). Открытие другого браузера приводит к увеличению количества дескрипторов и выделению большего количества ресурсов. Кроме того, эта проблема не устраняется путем специального вызова Dispose () для элемента управления WebBrowser. Код прост и выглядит следующим образом:

Главное окно:

<Window x:Class="WebBrowserMemory.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
            <Button Click="Button_Click">Gmail</Button>
        </StackPanel>
    </Grid>
</Window>

Button_Click:

private void Button_Click(object sender, RoutedEventArgs e)
{
    var win = new WebWindow();
    win.Show();
    win.Browser.Navigate("http://www.gmail.com");
}

Веб-окно:

<Window x:Class="WebBrowserMemory.WebWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WebWindow" Height="300" Width="300">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <WebBrowser Grid.Row="0" x:Name="_browser" />
    <Button Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10" Padding="10" Click="Button_Click">Close</Button>
</Grid>
</Window>

Соответствующий код:

public WebBrowser Browser {
    get { return _browser; }
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    Close();
}

protected override void OnClosed(EventArgs e)
        {
            _browser.Dispose();
            base.OnClosed(e);
        }

Кто-нибудь еще сталкивался с этой проблемой при использовании элемента управления WPF WebBrowser?

[ОБНОВЛЕНИЕ: обновленное сообщение для указания вызова Dispose () согласно ответу itowlson - даже вызов Dispose () в элементе управления веб-браузера не освобождает ресурсы]

Ответы [ 3 ]

8 голосов
/ 15 января 2010

В отличие от большинства элементов управления WPF, WebBrowser (поскольку он наследуется от HwndHost) является IDisposable и инкапсулирует неуправляемые ресурсы. Окно WPF, в отличие от формы WinForms, не автоматически удаляет свои дочерние элементы (поскольку собственные элементы управления WPF не инкапсулируют неуправляемые ресурсы и не требуют удаления).

Добавьте переопределение OnClosed в ваше окно (или обработайте событие Closed) и вызовите Dispose в элементе управления WebBrowser.

1 голос
/ 15 февраля 2013

Мне не удалось полностью устранить утечку, однако я заметил, что переход браузера к «about: blank» перед утилизацией определенно помогает уменьшить объем памяти, которая зависает.

1 голос
/ 15 января 2010

Вместо этого мы использовали элемент управления WinForm WebBrowser, который был создан внутри FormsHost в WPF, однако оба они работают практически одинаково с точки зрения пользовательского интерфейса, но мы обнаружили, что WebBrowser из WinForms обладает лучшей функциональностью и лучшей производительностью по сравнению с тем, который указан в WPF .

Вы можете вручную утилизировать WebBrowser элемента управления WinForm, который, безусловно, будет распоряжаться всеми своими дочерними и бесплатными ресурсами соответственно, однако, исходя из моего прошлого опыта, WinBorm WebBrowser не освобождает 100% своих ресурсов после закрытия, но да, это гораздо лучше, чем WPF.

...