System.Windows.Forms.WebBrowser memory leak issue
- 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)
### 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
Assessment
This issue has not been assessed yet.