![](/img/trans.png)
[英]Does *every* Excel interop object need to be released using Marshal.ReleaseComObject?
[英]Do I absolutely need to call ReleaseComObject on every MSHTML object?
我正在使用帶有WebBrowser控件的MSHTML,因為它讓我可以訪問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
對象的引用在第二代是這一個:
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顯示的內容:
我不知道那個站點容器是什么東西。
當RCW完成時,RCW將釋放COM對象,因此您不需要創建執行此操作的包裝器。 您調用ReleaseComObject
是因為您不想等待最終確定; 這與Dispose模式的原理相同。 所以創建可以Dispose
d的包裝器並不是一個壞主意(並且有一些例子
對於var doc = myBrowser.Document.DomDocument ...;
,你還應該在單獨的變量和ReleaseComObject
捕獲.Document
。 每次引用生成另一個對象的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;
}
}
這應該對您擁有的每個COM對象引用都要完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.