我正在使用带有WebBrowser控件的MSHTML,因为它让我可以访问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 "";
}
Run Code Online (Sandbox Code Playgroud)
不知道这里有什么问题,因为attribute它只是一个字符串.
这是ANTS分析器的实例保留图上显示的另一个函数(我添加了一堆FinalReleaseComObjects但仍然显示):
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;
}
}
Run Code Online (Sandbox Code Playgroud)
我添加了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;
}
}
Run Code Online (Sandbox Code Playgroud)
这MessageBox.Show("Couldn't release!");条线从未被击中,因此我认为一切都已正确发布.这是ANTS显示的内容:

我不知道那个站点容器是什么东西.
当RCW完成时,RCW将释放COM对象,因此您不需要创建执行此操作的包装器.你打电话ReleaseComObject是因为你不想等待最终确定; 这与Dispose模式的原理相同.所以创建可以是Disposed的包装器并不是一个坏主意(并且有一些例子
因为var doc = myBrowser.Document.DomDocument ...;,你也应该.Document在一个单独的变量中捕获ReleaseComObject它.每次引用生成另一个对象的COM对象的属性时,请确保释放它.
在GetAttribute,您将元素转换为另一个接口.在COM编程中,这增加了另一个参考.你需要做类似的事情var htmlElement = (IHTMLElement) element;,你也可以释放它.
编辑 - 这是使用COM对象时使用的模式:
IHTMLElement element = null;
try
{
element = <some method or property returning a COM object>;
// do something with element
}
catch (Exception ex) // although the exception type should be as specific as possible
{
// log, whatever
throw; // not "throw ex;" - that makes the call stack think the exception originated right here
}
finally
{
if (element != null)
{
Marshal.ReleaseComObject(element);
element = null;
}
}
Run Code Online (Sandbox Code Playgroud)
这应该对您拥有的每个COM对象引用都要完成.
| 归档时间: |
|
| 查看次数: |
2202 次 |
| 最近记录: |