这是.NET Webbrowser控件中一个众所周知的旧问题 .
简介:使用.NET webbrowser控件导航到页面会增加从未释放的内存使用量 .
重现内存泄漏:将WebBrowser控件添加到窗体 . 用它来导航到你想要的任何页面 . 关于:空白工作,向下滚动谷歌图像,直到你的使用量为100MB,然后在其他地方浏览,注意几乎没有任何内存被释放是一个更戏剧性的演示 .
我当前对应用程序的要求包括长时间运行它,显示有限的IE7浏览器窗口 . 运行IE7本身也有一些混蛋设置的钩子,BHO和组策略也是不可取的,尽管这看起来像是目前的后备 . 将浏览器嵌入到Windows窗体应用程序中 . 使用不同的浏览器基础对我来说不是一个可用的选项 . IE7是必需的 .
与此已知内存泄漏相关的先前主题和文章:
-
Memory leak when using WPF WebBrowser control in multiple windows
-
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/8a2efea4-5e75-4e3d-856f-b09a4e215ede
-
http://dotnetforum.net/topic/17400-appdomain-webbrowser-memory-leak/
通常提出的修复不起作用:
-
去不同的页面并不重要 . about:blank触发泄漏 . 它不需要页面具有javascript或任何其他额外技术 .
-
使用不同版本的Internet Explorer无关紧要 . 7,8和9都表现出相同的症状,据我所知,所有版本在控件中都有相同的内存泄漏 .
-
Dispose()控件无效 .
-
垃圾收集没有帮助 . (事实上,我对此进行的研究表明泄漏是在Webbrowswer控件包装的非托管COM代码中 . )
-
最小化并将进程可用内存设置为-1,-1(SetProcessWorkingSetSize()或simimlar . )仅减少物理内存使用量,对虚拟内存没有影响 .
-
调用WebBrowser.Stop()不是一个解决方案,并且打破了使用静态网页之外的任何功能的功能,而不仅仅是略微减少泄漏 .
-
在导航到另一个文档之前强制等待文档完全加载也无济于事 .
-
在单独的appDomain中加载控件无法解决问题 . (我自己没有这样做,但是研究显示其他人在这条路线上没有成功 . )
-
使用不同的包装器(如csexwb2)无济于事,因为这也会遇到同样的问题 .
-
清除Internet临时文件缓存不执行任何操作 . 问题出在活动内存中,而不是磁盘上 .
关闭并重新启动整个应用程序时,将清除内存 .
我愿意直接在COM或Windows API中编写自己的浏览器控件,如果这是对问题的肯定修复 . 当然,我更喜欢一个不太复杂的修复;我宁愿避免降低级别来做事情,因为我不想在浏览器支持的功能方面重新发明轮子 . 让我们在自己动手的浏览器中复制IE7功能和非标准行为 .
救命?
8 回答
这种泄漏似乎是非托管内存中的泄漏,因此您在进程中所做的任何事情都不会回收该内存 . 从你的帖子我可以看到你已经尝试避免泄漏相当广泛但没有成功 .
如果可行,我建议采用不同的方法 . 创建一个使用Web浏览器控件的单独应用程序,并从您的应用程序启动它 . 使用here描述的方法将新创建的应用程序嵌入到您自己的现有应用程序中 . 使用WCF或.NET远程处理与该应用程序通信 . 不时重新启动子进程以防止它占用大量内存 .
这当然是一个非常复杂的解决方案,重启过程可能看起来很难看 . 每次用户导航到另一个页面时,您可能会尝试重新启动整个浏览器应用程序 .
我拿了udione的代码(它对我有用,谢谢!)并改变了两件小事:
IKeyboardInputSite 是一个公共接口,方法 Unregister() ,因此在收到对* _keyboardInputSinkChildren *集合的引用后,我们不需要使用反射 .
由于视图并不总是直接引用其窗口类(特别是在MVVM中),我添加了一个方法 GetWindowElement(DependencyObject element) ,它通过遍历可视树返回所需的引用 .
谢谢,udione
谢谢你们!
有一种方法可以通过使用来清除内存泄漏反射和从mainForm上的私有字段中删除引用 . 这不是一个好的解决方案,但绝望的人在这里是代码:
在使用WPF WebBrowser组件从不同的方向(Win32 WorkingSet / COM SHDocVw接口等)与这个确切的 Out of Memory 问题进行了斗争之后,我发现我们的问题是 jqGrid 插件保持IE
ActiveXHost
中的非托管资源并且在调用WebBrowser.Dispose()
后没有释放它们 . 此问题通常由行为不正常的Javascript创建 . 奇怪的是,Javascript在常规IE中运行良好 - 只是不在WebBrowser
控件内 . 我猜测两个集成点之间的垃圾收集是不同的,因为IE永远不会真正关闭 .如果您正在编写源页面,我建议的一件事是删除所有JS组件并慢慢添加它们 . 一旦确定了有问题的JS插件(就像我们那样) - 应该很容易解决问题 . 在我们的例子中,我们只使用$("#jqgrid").jqGrid('GridDestroy')来正确删除它创建的事件和相关的DOM元素 . 当浏览器通过WebBrowser.InvokeScript关闭时,通过调用此问题来解决这个问题 .
如果您无法修改导航到的源页面,则必须在页面中注入一些JS来清理泄漏内存的DOM事件和元素 . 如果微软找到解决方案,那将是很好的,但是现在我们还在探索需要 cleansed 的JS插件 .
以下解决方案对我有用:
祝你好运,Layla
我认为这个问题在很长一段时间内都没有得到答复 . 这么多线程有相同的问题,但没有确定的答案 .
我已找到解决此问题的方法,并希望与您分享仍然面临此问题的所有人 .
step1:创建一个新表单,例如form2,并在其上添加一个Web浏览器控件 . 第2步:在您拥有webbrowser控件的form1中,只需将其删除即可 . step3:现在,转到Form2并将此webbrowser控件的访问修饰符设置为公共,以便可以在Form1中访问步骤4:在form1中创建一个面板并创建form2的对象并将其添加到面板中 . Form2 frm = new Form2(); frm.TopLevel = false; frm.Show(); panel1.Controls.Add(FRM);步骤5:定期调用下面的代码frm.Controls.Remove(frm.webBrowser1); frm.Dispose();
而已 . 现在,当您运行它时,您可以看到加载了webbrowser控件,它将定期处理,并且不再挂起应用程序 .
您可以添加以下代码,以提高效率 .
相信它更多的是.Net Framework问题而不是Web浏览器控件 . 使用处理程序连接到浏览器的导航事件,该处理程序将处理浏览器然后导航到about:blank将是一个很好的解决方法 . 例如:
尝试这个解决方案,我知道它不理想 . 每次加载页面后粘贴代码