我在IIS下有一个ASP.NET 2.0应用程序,它具有的功能 将一些数据导出到名为HFM的软件(Oracle Hyperion Financial Management)。 要执行该导出,.net应用程序使用基于HFM客户端提供的COM对象的API(客户端安装在与服务器等相同的机器上)
我的问题是API提供了一种连接HFM服务器但不断开连接的方法 文档说要断开连接,应用程序必须在创建的每个COM对象上调用 Marshal.ReleaseComObject()方法。 但是执行了很多复杂的操作,我无法释放所有创建的对象 所以我的应用程序不会断开连接。
我注意到当我替换ASP.NET应用程序的dll文件(它似乎重新启动.NET实例化的对象)时,应用程序会自动断开连接。
我试了几次电话:
GC.Collect();
GC.WaitForPendingFinalizers();
但问题仍然存在。 我正在寻找一种方法来确保创建任何对象,甚至COM对象都被释放。 我尝试使用 Marshal.FinalReleaseComObject()但是效果并不好。
当我在该部分放置一个lock()时,该部分上最多只有一个用户,所以我甚至可以使用硬核技术来释放COM对象。
有没有办法知道哪个对象或至少是尚未发布的对象类型?
感谢您的帮助。
答案 0 :(得分:2)
您是否可以在每个COM实例周围放置一个实现 IDisposable 的通用包装类型?
然后你可以在 Dispose 方法中调用 Marshal.FinalReleaseComObject (或循环 Marshal.ReleaseComObject 检查引用计数),并且只实例化COM对象通过引用您的包装类型的使用语句。
执行此包装技巧的另一个好处是,您可以使用CLR profiler检查尚未处理的类型实例,从而回答您的上一个问题。
答案 1 :(得分:1)
但是执行了很多复杂的操作,我无法释放所有创建的对象。
有你的问题。
你正在寻找一个简单的出路。但是你正在与COM合作。唯一容易的方法是关闭进程/ appdomain。
答案 2 :(得分:1)
在调用Marshal.ReleaseComObject或Marshal.FinalReleaseComObject后,将变量设置为Null / Nothing非常重要。
Dim cn As ADODB.Connection
cn = New ADODB.Connection
cn.Open(_cnnstr)
cn.Execute(sbDML.ToString)
cn.Close()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cn)
cn = Nothing '!!!IMPORTANT!!! - Do not remove, MUST be explicitly called!
此外,我注意到创建另一种方法有助于避免处理本地COM对象(放置在堆栈上的变量)的问题。例如,如果您有一个方法可以完成所有操作,请将其包装在另一个方法中,添加对垃圾收集的调用,然后调用包装器。
Public Sub MainMethod
'...
Marshal.FinalReleaseComObject(foo)
foo = Nothing '!!!IMPORTANT!!! - Do not remove, MUST be explicitly called!
End Sub
Public Sub WrapperMethod
Call MainMethod
GC.Collect()
End Sub
我相信额外的调用,通过为局部变量创建一个附加堆栈,可以更快地完全收集对象,并使COM对象完全释放。
我已经关注这种模式已经有几年了,自那以后我没有遇到任何问题。