C# 如何修复 IE WebBrowser 控件中的内存泄漏?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/904478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 02:28:29  来源:igfitidea点击:

How to Fix the Memory Leak in IE WebBrowser Control?

c#winformsmemory-leakswebbrowser-control

提问by Rainer Falle

I am trying to embed a WebBrowser Control in a C# Winform Application. This sounds easy enough. However I discovered that the WebBrowser control eats up a lot of memory every time I call the Navigate method. The memory is never released. The memory usage grows and grows…

我正在尝试在 C# Winform 应用程序中嵌入一个 WebBrowser 控件。这听起来很容易。但是我发现每次调用 Navigate 方法时,WebBrowser 控件都会占用大量内存。内存永远不会被释放。内存使用量越来越大……

Many people on the net having the exact same problem but I haven't found a satisfying answer yet. This is the best discussions about this issue I found so far:

网上很多人都有同样的问题,但我还没有找到令人满意的答案。这是迄今为止我发现的有关此问题的最佳讨论:

Memory Leak in IE WebBrowser Control

IE WebBrowser 控件中的内存泄漏

One person suggested an upgrade to IE8 to fix the problem.

有人建议升级到 IE8 来解决这个问题。

However I need a solution that works whether the user has the latest IE version installed or not. I do not have control over the users environment.

但是,无论用户是否安装了最新的 IE 版本,我都需要一个有效的解决方案。我无法控制用户环境。

Does anybody know how to release the memory taken by the WebBrowser control? Are there workarounds? Are there alternatives to the WebBrowser control?

有人知道如何释放 WebBrowser 控件占用的内存吗?有解决方法吗?是否有 WebBrowser 控件的替代品?

Update:I just did a few more tests. At work I am running Windows XP and IE6. The memory is not growing there. The memory increases when calling the navigate method but is being released after a while. At home I am running Vista and upgraded to IE8. Here I also do not see the problem anymore. It looks like the issue is specific to IE7. So the question should be rephrased to "How to Fix the Memory Leak in IE WebBrowser Control when IE7 is installed". Can anybody confirm that this problem is specific to IE7?

更新:我只是做了一些更多的测试。在工作中,我运行的是 Windows XP 和 IE6。记忆没有在那里增长。调用导航方法时内存会增加,但会在一段时间后释放。在家里我运行Vista并升级到IE8。在这里我也看不到问题了。看起来这个问题是特定于 IE7 的。所以问题应该改写为“安装 IE7 时如何修复 IE WebBrowser Control 中的内存泄漏”。任何人都可以确认这个问题是特定于 IE7 的吗?

回答by Beatles1692

I'm using the Web Control in an application but since my application navigates to one page only I haven't noticed the issue you mentioned. There's another web control that is actually a wrapper and I don't know if it has the same problem or not. You can find it here.

我在应用程序中使用 Web 控件,但由于我的应用程序仅导航到一页,因此我没有注意到您提到的问题。还有另一个 web 控件实际上是一个包装器,我不知道它是否有同样的问题。你可以在这里找到它。

回答by Matt Brindley

There's an alternative controlthat uses Gecko (The engine Firefox uses) instead of Trident and works very well with the MSHTML interfaces.

有一个替代控件使用 Gecko(Firefox 使用的引擎)而不是 Trident,并且与 MSHTML 界面配合得很好。

Your pages will render in Gecko, and you'll have complete control over the settings, plugins, security and any other customisable features of a browser.

您的页面将在 Gecko 中呈现,并且您可以完全控制浏览器的设置、插件、安全性和任何其他可定制功能。

The downside is that you'll need to ship Gecko with your app, I last used the equivalent of Firefox 2 and it was around 8MB.

缺点是您需要随应用程序一起提供 Gecko,我上次使用的是相当于 Firefox 2 的版本,它大约为 8MB。

I released an app quite a while ago that compared IE and Firefox rendering alongside each other, both updating as you edited the CSS. I didn't run into the memory problems you've had with the web browser control, but I found the Gecko control very easy to work with. It doesn't have the same managed wrapper class that the .net WebBrowser control has, but it's easy enough to work around that.

很久以前我发布了一个应用程序,它比较了 IE 和 Firefox 的渲染,两者都在您编辑 CSS 时更新。我没有遇到您在使用 Web 浏览器控件时遇到的内存问题,但我发现 Gecko 控件非常易于使用。它没有与 .net WebBrowser 控件相同的托管包装类,但很容易解决这个问题。

回答by BFree

I just created a simple app with a web browser control to try and duplicate your results. What I found was that yes, every time you navigate to a page, the memory being used increases significantly. HOWEVER, this is NOT a memory leak, because if you keep navigating, you'll see that after a short while, the memory drops significantly, indicating that the garbage collector did it's thing. To prove it, I forced the Garbage Collector to collect after every time I called Navigate, and the overall memory used stayed put at almost the same amount after every navigate call.

我刚刚创建了一个带有 Web 浏览器控件的简单应用程序来尝试复制您的结果。我发现是的,每次导航到一个页面时,所使用的内存都会显着增加。然而,这不是内存泄漏,因为如果您继续导航,您会看到不久之后,内存显着下降,这表明垃圾收集器做了它的事情。为了证明这一点,我在每次调用 Navigate 后强制垃圾收集器收集,并且每次导航调用后使用的总内存几乎保持不变。

So while it DOES rack up memory every time you "Navigate" it's NOT a memory leak, and you the memory will be released. If it's raking up too quickly, just call GC.Collect();

因此,虽然每次“导航”时它都会占用内存,但它不是内存泄漏,您的内存将被释放。如果它上升太快,只需调用 GC.Collect();

回答by BFree

I was running into the same problem, as an alternative, instead of navigating to a new page, I simply rewrote the same html page using the system.oi.streamreader/writer object and calling a refresh. Obviously that won't work in a situation where content for the browser is being fed online, but it's doing the trick for me.

我遇到了同样的问题,作为替代方法,我没有导航到新页面,而是使用 system.oi.streamreader/writer 对象重新编写了相同的 html 页面并调用了刷新。显然,这在浏览器内容在线提供的情况下不起作用,但它对我有用。

Also, I'm currently using 8+ browser controls all active at the same time to serve reporting through javascript inside my .net app. As a user makes one browser active, the html to which the other browsers are pointing, are cleared and the browsers refreshed. With 8 browsers running with these two methods I can easily keep my app well under the memory usage of Firefox with just 3 tabs open.

此外,我目前正在使用 8 个以上的浏览器控件同时处于活动状态,以通过 .net 应用程序中的 javascript 提供报告。当用户激活一个浏览器时,其他浏览器指向的 html 将被清除并刷新浏览器。通过使用这两种方法运行 8 个浏览器,我可以轻松地将我的应用程序保持在 Firefox 的内存使用范围内,而只需打开 3 个选项卡。

回答by Dave Black

There is a known Memory Leak in the WebBrowser control. See the following Microsoft KB article - KB893629.

WebBrowser 控件中存在已知的内存泄漏。请参阅以下 Microsoft 知识库文章 - KB893629

回答by womd

my app was also constantly consuming memory when navigating, and not releasing anymore. i fount the solution for me here: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/88c21427-e765-46e8-833d-6021ef79e0c8

我的应用程序在导航时也不断消耗内存,不再释放。我在这里为我找到了解决方案:http: //social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/88c21427-e765-46e8-833d-6021ef79e0c8

for completeness ill post the notable excerpt:

为了完整起见,请发布值得注意的摘录:

-- in class definition

    [DllImport("KERNEL32.DLL", EntryPoint = "SetProcessWorkingSetSize", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    internal static extern bool SetProcessWorkingSetSize(IntPtr pProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize);

    [DllImport("KERNEL32.DLL", EntryPoint = "GetCurrentProcess", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    internal static extern IntPtr GetCurrentProcess();

-- code to call when you want to reduce the memory

-- 当你想减少内存时调用的代码

        IntPtr pHandle = GetCurrentProcess();
        SetProcessWorkingSetSize(pHandle, -1, -1);

all honors to: http://social.msdn.microsoft.com/profile/mike_t2e/?type=forum&referrer=http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/88c21427-e765-46e8-833d-6021ef79e0c8for posting the solution.

所有荣誉:http: //social.msdn.microsoft.com/profile/mike_t2e/?type=forum&referrer= http: //social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/88c21427-e765 -46e8-833d-6021ef79e0c8用于发布解决方案。

and http://ict-engineer.blogspot.com/2010/10/net-webbrowser-control-memory-leak.htmlfor SEO'ing it right, so i could find it ;)

http://ict-engineer.blogspot.com/2010/10/net-webbrowser-control-memory-leak.html用于 SEO 正确,所以我可以找到它;)

greetings

你好

edit: if this helps you to quickly solve an issu - good. but you should overthing your application design, the pattern you use if any , refactore the thing if you build onto that much longer ....

编辑:如果这有助于您快速解决问题 - 很好。但是你应该改变你的应用程序设计,你使用的模式(如果有的话),如果你构建的时间更长,就重构它......

回答by Layla

I looked all over the internet and I was unable to find an answer to this problem. I fixed it using the below:

我查看了整个互联网,我无法找到这个问题的答案。我使用以下方法修复了它:

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

        '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()

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

        'vb.net for some reason automatically recreates these and the below is not needed
        '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)
        'webDollar.Navigate(webdollarNavigate)
        disposeOfBrowsers = Now.AddMinutes(20)
    End If
End Sub

I know this is not the prettiest or perfect solution, but it worked very well for me. -- Layla

我知道这不是最漂亮或完美的解决方案,但它对我来说效果很好。——莱拉

回答by Stefan Kruger

Paste the following code after page load

页面加载后粘贴以下代码

System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
try
{
     loProcess.MaxWorkingSet = (IntPtr)((int)loProcess.MaxWorkingSet - 1);
     loProcess.MinWorkingSet = (IntPtr)((int)loProcess.MinWorkingSet - 1);
}
catch (System.Exception)
{
     loProcess.MaxWorkingSet = (IntPtr)((int)1413120);
     loProcess.MinWorkingSet = (IntPtr)((int)204800);
}

回答by nh53019

I think this question has gone unanswered for a long time now. So many threads with the same question but not conclusive answer.

我想这个问题已经很久没有答案了。这么多线程有相同的问题,但没有决定性的答案。

I have found a work around for this issue and wanted to share with you all who are still facing this issue.

我找到了解决此问题的方法,并希望与所有仍然面临此问题的人分享。

step1: Create a new form say form2 and add a web-browser control on it. step2: In the form1 where you have your webbrowser control, just remove it. step3: Now, go to Form2 and make the access modifier for this webbrowser control to be public so that it can be accessed in Form1 step4: Create a panel in form1 and create object of form2 and add this into panel. Form2 frm = new Form2 (); frm.TopLevel = false; frm.Show(); panel1.Controls.Add(frm); step5: Call the below code at regular intervals frm.Controls.Remove(frm.webBrowser1); frm.Dispose();

步骤 1:创建一个新表单,例如 form2 并在其上添加一个 Web 浏览器控件。步骤 2:在您拥有 webbrowser 控件的 form1 中,只需将其删除。step3:现在,转到Form2,将这个webbrowser控件的访问修饰符设置为public,以便在Form1中可以访问它 step4:在form1中创建一个面板并创建form2的对象并将其添加到面板中。Form2 frm = new Form2(); frm.TopLevel = 假;frm.Show(); panel1.Controls.Add(frm); step5:定期调用下面的代码 frm.Controls.Remove(frm.webBrowser1); frm.Dispose();

Thats it. Now when you run it, you can see that webbrowser control loaded and it will get disposed at regular intervals and there is no more hanging of the application.

就是这样。现在,当您运行它时,您可以看到已加载 webbrowser 控件,它将定期处理,并且应用程序不再挂起。

You can add the below code to make it more efficient.

您可以添加以下代码以提高效率。

    IntPtr pHandle = GetCurrentProcess();
    SetProcessWorkingSetSize(pHandle, -1, -1);


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

回答by D-Jones

I ran into this problem while writing a small "slideshow" application for different intranet pages used by my company. The simplest solution I found was restarting the application after some fixed period of time, an hour in my case. This solution worked well for us because there wasn't a lot of user interaction with the browser.

我在为我公司使用的不同 Intranet 页面编写一个小的“幻灯片”应用程序时遇到了这个问题。我找到的最简单的解决方案是在一段固定的时间后重新启动应用程序,在我的情况下是一个小时。这个解决方案对我们来说效果很好,因为用户与浏览器的交互并不多。

Public Class MyApplication

    Private _AppTimer As Timers.Timer

    Public Sub New()
        _AppTimer = New Timers.Timer()
        _AppTimer.Interval = 1 * 60 * 60 * 1000 '1 Hour * 60 Min * 60 Sec * 1000 Milli

        AddHandler _AppTimer.Elapsed, AddressOf AppTimer_Elapsed

        _AppTimer.Start()
    End Sub

    Private Sub AppTimer_Elapsed(s As Object, e As Timers.ElapsedEventArgs)
        Application.Restart()
    End Sub

End Class

This assumes of course that you have a data persistence mechanism in place.

这当然假设您有一个适当的数据持久性机制。