gpt4 book ai didi

c# - 我绝对需要在每个 MSHTML 对象上调用 ReleaseComObject 吗?

转载 作者:太空狗 更新时间:2023-10-29 20:17:31 27 4
gpt4 key购买 nike

我将 MSHTML 与 WebBrowser 控件一起使用,因为它使我可以访问 WebBrowser 无法访问的内容,例如文本节点。我在这里和网络上看到过一些帖子,人们说您必须为您引用的每个 COM 对象调用 ReleaseComObject。所以,假设我这样做:

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 分析器的实例保留图上显示的另一个函数(我添加了一堆 FinalReleaseComObject 但仍然显示):

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 显示的内容:

ANTS memory profiler screenshot

我不知道那个站点容器是什么。

最佳答案

RCW 将在 RCW 完成时释放 COM 对象,因此您无需创建执行此操作的包装器。您调用 ReleaseComObject 是因为您不想等待完成;这与 Dispose 模式的原理相同。因此,创建可以被 Dispose 处理的包装器并不是一个坏主意(并且有一些示例

对于 var doc = myBrowser.Document.DomDocument ...;,您还应该在单独的变量和 ReleaseComObject 中捕获 .Document它也是。任何时候您引用生成另一个对象的 COM 对象的属性时,请务必释放它。

GetAttribute 中,您将元素转换为另一个接口(interface)。在 COM 编程中,that adds another reference .您需要执行类似 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;
}
}

这确实应该为您拥有的每个 COM 对象引用完成。

关于c# - 我绝对需要在每个 MSHTML 对象上调用 ReleaseComObject 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14789652/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com