我正在研究一个网络刮刀,它的生长效果非常好。它将在大多数网站上浏览数千页并成功完成,没有任何问题。
在一些网站上,我反复看到同样的问题。
Insufficient memory to continue the execution of the program.
修改 我使用perfmon来确定泄漏发生在非托管内存中。 我知道因为“私有字节”在程序运行时不断增加,而所有堆中的字节都保持稳定。
(实际上,它会上升和下降,但逐渐攀升。它通常在我上面列出的代码部分内存不足,但我不认为该部分是原因,而是可能是第一个受害者,因为它使用了很多记忆...我认为它后来发布它虽然)
编辑2:
我按照本网站上的说明操作: http://www.codeproject.com/Articles/42721/Best-Practices-No-5-Detecting-NET-application-memo
我使用debugDiag检查程序。
在分析数据后,调试diag告诉我造成泄漏的原因是什么:
jscript.dll is responsible for 1.10 GBytes worth of outstanding allocations. The following are the top 2 memory consuming functions:
jscript!Parser::GenerateCode+167: 498.19 MBytes worth of outstanding allocations.
jscript!NoRelAlloc::PvAlloc+96: 292.99 MBytes worth of outstanding allocations.
我没有在我的应用程序中引用jscript.dll,它必须被我正在使用的Web浏览器控件使用。
System.Windows.Forms.WebBrowser
至少我是猜测。
我还收到一个消息框,其中弹出标题为“来自网页的消息”,其中显示的内容是“第X行内存不足”。
所以,我想我可以处理webbrowser对象并恢复我的记忆 - 所以我添加了一个包含以下代码的按钮:
Me.wbMain.Dispose() 'dispose all of thwe web-browsers
frmDebugger.wbDebugMain.Dispose()
Me.WBNewWin.Dispose()
GC.Collect() 'just for the heck of it
所以,在运行一段时间后,我停止了抓取并点击了我的新按钮......它根本没有任何区别。我在perfmon中观看了总的“私人字节”,它甚至没有移动。
任何想法,任何人?
编辑3:
我尝试了一系列推荐的解决方案,但似乎都没有。
有人建议可能是由于图像没有从缓存中清除,但我禁止加载图像,所以我知道这不是问题。
我也听说IE7有问题,升级到IE8会解决它。我有IE8,它仍然会泄漏内存。
有人建议使用webbrowser控件最小化窗体会释放一些内存。我试过了,但没有什么区别。
我也被告知我不应该期待内存使用只是丢弃,因为我将不得不等待垃圾收集器。它不是托管代码中的泄漏,因此GC.Collect()不会执行任何操作。它处于非托管内存中。显然,javascript功能使用不同的内存,并且没有手动方式来强制收集。但它已经到了崩溃的地步,所以显然存在问题。
我正在为这个问题添加50的赏金,我将奖励给任何帮助我解决泄漏问题的人。我想尝试这个解决方案: http://www.codeproject.com/Questions/322884/WPF-WebBrowser-control-vs-Internet-Explorer-browse 但我无法弄清楚vb.net的等价物是什么。我尝试过在线转换器,转换此代码时出错(尽管它们适用于我过去转换过的其他代码)
如果我无法解决泄漏问题,我会将其授予任何将上述页面从c#转换为vb.net的人。
我的后备计划是创建一个单独的应用程序,它只包含webbrowser,并与该进程通信,直到内存不足为止,此时我将重新启动它(当我完全覆盖我的应用程序时内存被释放)。这对我的应用程序来说远非理想,因为webbrowser非常紧密地编入我的项目中。
编辑4
我尝试实现建议的javascript注入 - 这是我的代码:
(我在导航到新页面之前将其解雇)
Public Shared Sub Clean_JS(ByRef wb As System.Windows.Forms.WebBrowser)
Dim args As Object() = {"document.body"}
Dim head As HtmlElement = wb.Document.GetElementsByTagName("head")(0)
Dim scriptEl0 As HtmlElement = wb.Document.CreateElement("script")
Dim element0 As mshtml.IHTMLScriptElement = DirectCast(scriptEl0.DomElement, mshtml.IHTMLScriptElement)
element0.text = "function ReleaseHandler() {" + vbCrLf + " var EvtMgr = (function() {" + vbCrLf + " var listenerMap = {};" + vbCrLf + " " + vbCrLf + " // Public interface" + vbCrLf + " return {" + vbCrLf + " addListener: function(evtName, node, handler) {" + vbCrLf + " node[""on"" + evtName] = handler;" + vbCrLf + " var eventList = listenerMap[evtName];" + vbCrLf + " if (!eventList) {" + vbCrLf + " eventList = listenerMap[evtName] = [];" + vbCrLf + " }" + vbCrLf + " eventList.push(node);" + vbCrLf + " }," + vbCrLf + " " + vbCrLf + " removeAllListeners: function() {" + vbCrLf + " for (var evtName in listenerMap) {" + vbCrLf + " var nodeList = listenerMap[evtName];" + vbCrLf + " for (var i = 0, node; node = nodeList[i]; i++) {" + vbCrLf + " node[""on"" + evtName] = null;" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " })();" + vbCrLf + " }"
head.AppendChild(scriptEl0)
Dim scriptEl1 As HtmlElement = wb.Document.CreateElement("script")
Dim element1 As mshtml.IHTMLScriptElement = DirectCast(scriptEl1.DomElement, mshtml.IHTMLScriptElement)
element1.text = "function ReleaseHandler() {" + vbCrLf + " var EvtMgr = (function() {" + vbCrLf + " var listenerMap = {};" + vbCrLf + " " + vbCrLf + " // Public interface" + vbCrLf + " return {" + vbCrLf + " addListener: function(evtName, node, handler) {" + vbCrLf + " node[""on"" + evtName] = handler;" + vbCrLf + " var eventList = listenerMap[evtName];" + vbCrLf + " if (!eventList) {" + vbCrLf + " eventList = listenerMap[evtName] = [];" + vbCrLf + " }" + vbCrLf + " eventList.push(node);" + vbCrLf + " }," + vbCrLf + " " + vbCrLf + " removeAllListeners: function() {" + vbCrLf + " for (var evtName in listenerMap) {" + vbCrLf + " var nodeList = listenerMap[evtName];" + vbCrLf + " for (var i = 0, node; node = nodeList[i]; i++) {" + vbCrLf + " node[""on"" + evtName] = null;" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " })();" + vbCrLf + " }"
head.AppendChild(scriptEl1)
wb.Document.InvokeScript("ReleaseHandler")
wb.Document.InvokeScript("purge", args)
End Sub
不幸的是,我仍然看到perfmon中的私有字节增加。
任何人都可以在我的逻辑中看到任何缺陷吗?我正在尝试实现此修复: http://www.codeproject.com/Questions/322884/WPF-WebBrowser-control-vs-Internet-Explorer-browse
btw - 我使用简单的代码测试它,如下:
object[] args = {"my important message"};
webBrowser1.Document.InvokeScript("alert",args);
和此:
Dim head As HtmlElement = wb.Document.GetElementsByTagName("head")(0)
Dim scriptEl As HtmlElement = wb.Document.CreateElement("script")
Dim element As mshtml.IHTMLScriptElement = DirectCast(scriptEl.DomElement, mshtml.IHTMLScriptElement)
element.text = "function sayHello() { alert('hello') }"
head.AppendChild(scriptEl)
wb.Document.InvokeScript("sayHello")
它在两个测试用例中都显示了消息。
奇怪的是,当我尝试通过这样做来测试脚本注入时:
Dim head As HtmlElement = wbMain.Document.GetElementsByTagName("head")(0)
Dim scriptEl As HtmlElement = wbMain.Document.CreateElement("script")
Dim element As mshtml.IHTMLScriptElement = DirectCast(scriptEl.DomElement, mshtml.IHTMLScriptElement)
element.text = "function sayHello() { alert('hello') }"
head.AppendChild(scriptEl)
wbMain.Document.InvokeScript("sayHello")
RTB_RawHTML.Text = "TEST" + vbCrLf + wbMain.DocumentText
我没有看到注入的代码反映在文本框中 - 我看到的唯一变化是出现了“test”这个词(当页面完成从documentCompleted事件加载时,我运行代码RTB_RawHTML.Text = wbMain.DocumentText .. 。)
答案 0 :(得分:0)
您引用的文章中的代码不是C#,而是Javascript。我相信这个想法是将JS注入你的HTML页面,这样它就可以在页面卸载时运行,这将清除现有的JS事件。
您可以查看本文,将JS添加到WebBrowser控件中的页面:
http://www.codeproject.com/Articles/94777/Adding-a-Javascript-Block-Into-a-Form-Hosted-by-We
Dim scriptText As String =
<string>
function ReleaseHandler() {
var EvtMgr = (function() {
var listenerMap = {};
// Public interface
return {
addListener: function(evtName, node, handler) {
node["on" + evtName] = handler;
var eventList = listenerMap[evtName];
if (!eventList) {
eventList = listenerMap[evtName] = [];
}
eventList.push(node);
},
removeAllListeners: function() {
for (var evtName in listenerMap) {
var nodeList = listenerMap[evtName];
for (var i = 0, node; node = nodeList[i]; i++) {
node["on" + evtName] = null;
}
}
}
}
})();
}
function purge(d){
var a = d.attributes, i, l, n;
if (a) {
for (i = a.length - 1; i >= 0 ; i -= 1) {
n = a[i].name;
if (typeof d[n] === 'function') {
d[n] = null;
}
}
}
a = d.childNodes;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
purge(d.childNodes[i]);
}
}
}
<string>
Dim head As HtmlElement = webBrowser1.Document.GetElementsByTagName("head")(0)
Dim script As HtmlElement = webBrowser1.Document.CreateElement("script")
Dim domElement As IHTMLScriptElement = CType(script.DomElement, IHTMLScriptElement)
domElement.text = scriptText
head.AppendChild(script)
我没有测试过这段代码(我不确定我是怎么做的,因为你自己没有提供示例代码)...这更像是对你如何进行的建议。我从来没有尝试过将JS插入到WebBrowser控件中,所以我不太清楚如何执行它(因为理论上,JS在加载页面后已经执行了,因此你注入的JS会“迟到了”。)
您还需要找到一种方法来连接文档,以便在卸载时调用这两个函数。我们的想法是通过消除JS对象和事件来消除JS内存泄漏,因此简单地声明函数是不够的。我在网上看到很多文章讨论了如何在WebBrowser控件中破坏OnBeforeUnload事件(它没有正确触发),所以你可能会为你做很多工作。
答案 1 :(得分:0)
可能是您可以尝试使用不将cookie保存到用户计算机的代码。导致临时项目可以向用户计算机发出几个问题