views:

735

answers:

2

I am working on a project that makes use of the WPF WebBrowser control (System.Windows.Controls.WebBrowser). The web browser element of the program is one of many activities the user can engage in, and is opened in a separate window. After the user navigates away from the browser, the window is closed, and a new window is created each time the user returns to the browser. We were noticing a significant memory leak / performance downgrade in our program (usage getting up to ~700mb from ~200 initial) upon continually using the browser. After failing to find any points of resource leaks within our own code, I decided to determine if the issue was with our own WebBrowser wrapper control, or the WPF control.

I created a new simple project consisting of only a MainWindow and a WebWindow. A button on the main window launches a browser directed at gmail (the site we noticed the biggest issue with of the few we examined). Upon closing this window, there is no freeing of resources (no reduction in VM size in Task Manager or Process Explorer) and the number of GDI objects the process has handles to does not decrease (the program starts with ~30, opening the browser takes it to ~140 and after closing the browser ~140 are still open). Opening another browser causes more handles, and more resources to be allocated. Furthermore, this problem is not fixed by specifically calling Dispose() on the WebBrowser control. The code is simple, and is as follows:

Main Window:

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

Web Window:

<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>

Relevant Code:

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

Has anyone else encountered this issue using the WPF WebBrowser control?

[UPDATE: Updated post to indicate Dispose() call as per itowlson's answer - even calling Dispose() on the web browser control does not free the resources]

+1  A: 

Unlike most WPF controls, WebBrowser (because it inherits from HwndHost) is IDisposable and encapsulates unmanaged resources. The WPF Window, unlike the WinForms Form, does not automatically dispose its children (because native WPF controls do not encapsulate unmanaged resources and do not require disposal).

Add an OnClosed override to your window (or handle the Closed event), and call Dispose on the WebBrowser control.

itowlson
Sorry, forgot about Dispose, the actual project I am working on does call the Dispose method, I just forgot to add it to my demo app. Calling Dispose explicitly unfortunately doesn't fix the problem. A handful of GDI handles are released, but the vast majority stay open. Updated my post to indicate Dispose() is explicitly called
jeffora
+1  A: 

We instead used WinForm WebBrowser control, which was created inside FormsHost in WPF, however both work pretty same from the UI point of view, but we have found that WebBrowser of WinForms has better functionality and better performance compared to one given in WPF.

You can manually dispose WebBrowser of WinForm control that will certainly dispose all of its children and free resources accordingly, however with my past experience, WinForm's WebBrowser does not release 100% of its resources after closing, but yes it is far better then WPF.

Akash Kava