我将 MSHTML 与 WebBrowser 控件一起使用,因为它使我可以访问 WebBrowser 不具备的内容,例如文本节点。我在这里和网络上看到过一些帖子,人们说您必须ReleaseComObject
为您引用的每个 COM 对象调用。所以,假设我这样做:
var doc = myBrowser.Document.DomDocument as IHTMLDocument2;
我需要释放doc
吗?如何body
在此代码中:
var body = (myBrowser.Document.DomDocument as IHTMLDocument2).body;
这些对象不是由 RCW 包装的,一旦不再引用它们就会释放它们吗?如果不是,最好使用终结器(而不是使用 Dispose)为它们中的每一个创建一个包装器,该终结器会在垃圾收集器启动后立即释放它们(这样我就不需要担心手动处置它们)?
问题是,我的应用程序有内存泄漏,我相信与此有关。根据 ANTS 内存分析器,其中一个函数(以及许多其他碰巧使用 MSHTML 对象的函数)持有对一组Microsoft.CSharp.RuntimeBinder.Semantics.LocalVariableSymbol
对象的引用,这些对象位于第 2 代中使用内存的对象的顶部列表中:
internal static string GetAttribute(this IHTMLDOMNode element, string name)
{
var attribute = element.IsHTMLElement() ? ((IHTMLElement)element).getAttribute(name) : null;
if (attribute != null) return attribute.ToString();
return "";
}
不知道这里出了什么问题,因为attribute
只是一个字符串。
这是 ANTS profiler 的 Instance Retention Graph 上显示的另一个函数(我添加了一堆FinalReleaseComObject
s 但仍然显示):
private void InjectFunction(IHTMLDocument2 document)
{
if (null == Document) throw new Exception("Cannot access current document's HTML or document is not an HTML.");
try
{
IHTMLDocument3 doc3 = document as IHTMLDocument3;
IHTMLElementCollection collection = doc3.getElementsByTagName("head");
IHTMLDOMNode head = collection.item(0);
IHTMLElement scriptElement = document.createElement("script");
IHTMLScriptElement script = (IHTMLScriptElement)scriptElement;
IHTMLDOMNode scriptNode = (IHTMLDOMNode)scriptElement;
script.text = CurrentFuncs;
head.AppendChild(scriptNode);
if (Document.InvokeScript(CurrentTestFuncName) == null) throw new Exception("Cannot inject Javascript code right now.");
Marshal.FinalReleaseComObject(scriptNode);
Marshal.FinalReleaseComObject(script);
Marshal.FinalReleaseComObject(scriptElement);
Marshal.FinalReleaseComObject(head);
Marshal.FinalReleaseComObject(collection);
//Marshal.FinalReleaseComObject(doc3);
}
catch (Exception ex)
{
throw ex;
}
}
我添加了,ReleaseComObject
但该函数似乎仍然持有对某些东西的引用。这是我的函数现在的样子:
private void InjectFunction(IHTMLDocument2 document)
{
if (null == Document) throw new Exception("Cannot access current document's HTML or document is not an HTML.");
try
{
IHTMLDocument3 doc3 = document as IHTMLDocument3;
IHTMLElementCollection collection = doc3.getElementsByTagName("head");
IHTMLDOMNode head = collection.item(0);
IHTMLElement scriptElement = document.createElement("script");
IHTMLScriptElement script = (IHTMLScriptElement)scriptElement;
IHTMLDOMNode scriptNode = (IHTMLDOMNode)scriptElement;
script.text = CurrentFuncs;
head.AppendChild(scriptNode);
if (Document.InvokeScript(CurrentTestFuncName) == null) throw new Exception("Cannot inject Javascript code right now.");
Marshal.FinalReleaseComObject(scriptNode);
Marshal.FinalReleaseComObject(script);
Marshal.FinalReleaseComObject(scriptElement);
Marshal.FinalReleaseComObject(head);
Marshal.FinalReleaseComObject(collection);
Marshal.ReleaseComObject(doc3);
}
catch (Exception ex)
{
MessageBox.Show("Couldn't release!");
throw ex;
}
}
这MessageBox.Show("Couldn't release!");
条线永远不会被击中,所以我认为一切都已正确发布。以下是 ANTS 显示的内容:
我不知道那个站点容器是什么。