dotnet / dotnet/winforms

System.Windows.Forms.WebBrowser memory leak issue

Open
#13,769 4 comments 0 reactions 0 assignees View on GitHub
area-COM tenet-performance
Dominant language
C#
Stars
4.9k
Forks
1.1k
Avg merge
20h 23m
Merged PRs (30d)
103

Description

### .NET version

We are migrating our software from .NET framework 4.8 to .NET core 8.0

### Did it work in .NET Framework?

Yes

### Did it work in any of the earlier releases of .NET Core or .NET 5+?

Yes, it works in .NET 7

### Issue description

I suspect that the `System.Windows.Forms.WebBrowser` has a memory leak issue in .NET 8.0 and 9.0.

Please see the repro code in `Step to reproduce` section.

### Context
Our team is trying to migrate our software from .NET framework 4.8.1 into .NET core 8.0.
We have a class called `ZWebBrowser : WebBrowser`. Any test that deals with this class, even just create this object alone, will fail. `ZWebBrowser` only add extra keys handlers, so I don't think it causes the un-GC issue above.

We know that `WebBrowser` is advised against, however, due to resources issue, we cannot abandon it.

Here is the memory profiler result on .NET core 8, showing that the inner class `WebBrowserSite` and `WebBrowserEvent` have (strong) [RefCounted handle](https://www.jetbrains.com/help/dotmemory/Analyzing_GC_Roots.html#refcounted-handle) root, which does not let them get garbage collected. In .NET framework 4.8, these roots are [Weak, RefCounted handle](https://www.jetbrains.com/help/dotmemory/Analyzing_GC_Roots.html#weak-handle)

Image

### Steps to reproduce

Based on the test below, the wrapped `WebBrowser` object is garbage collected:
- NOT successfully in .NET Core 8.0 and 9.0
- successfully in .NET Core 7.0 + .NET Framework 4.8.1

```csharp

using System.Runtime.CompilerServices;

namespace WinFormsTest
{
public static class WebBrowserTests
{
public static void TestRunLeak()
{
var browserWeakRef = CreateWebBrowser();

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

var isBrowserGC = !browserWeakRef.IsAlive;

// NET CORE 8.0+: isBrowserGC is false;
// NET CORE 7.0: isBrowserGC is true;
// NET Framework 4.8: isBrowserGC is true;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static WeakReference CreateWebBrowser()
{
using (var browser = new System.Windows.Forms.WebBrowser())
{
browser.Navigate("about:blank");
return new WeakReference(browser);
}
}
}
}
```
### Extra
When diffing the .NET 7.0 and 8.0 source code, this code looks suspicious
https://github.com/dotnet/winforms/blob/e9badd948720225f73defcafa0bccac3011b3256/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs#L690C43-L690C54

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.