【问题标题】:Access violation in WCF with COM object after garbage collection垃圾回收后 WCF 中的访问冲突与 COM 对象
【发布时间】:2014-05-01 22:47:18
【问题描述】:

我有一个自托管的 WCF 应用程序,其中服务对象(每次调用,单个并发)使用构建在名为 Clarion 的平台上的嵌入式 COM 对象(在整个调用过程中从类中引用)。 COM 实例与服务对象一起创建和销毁。然而,他们在下面访问一个需要很长时间来初始化的单例存储库(与此非常相似:Startup Code for Loading COM Object for WCF Service)。所以第一次通话很长。因此,我必须在启动时调用它。

如果我在启动时不实例化 COM 对象,一切都很好(除了第一次调用很长)。但是如果我这样做了,在垃圾收集之后,下一个请求将在尝试访问 COM 时因访问冲突异常而崩溃。

服务对象实现IDisposable,其中所有COM对象都使用Marshal.ReleaseComObject很好地释放。 启动调用还释放 COM 对象。

我的猜测是启动 COM 以某种方式被重用或回收。我不想要它!我能确保它永远死去吗?或者如果不可能,我可以将其标记为不用于垃圾收集吗?显然,GC.KeepAlive 在这里是无关紧要的,因为这些是不同方法中的不同线程。

更多细节:COM 对象最近支持 MTA。它们是线程安全的和完全并发的,但是在之前,当它们只是 STA 时,没有这样的问题。此外,当这些人在单独的线程中运行时,在 WCF 之外不会发生任何不好的事情。

【问题讨论】:

  • 在不显式调用Marshal.ReleaseComObject 的情况下尝试一下。检查"Marshal.ReleaseComObject Considered Dangerous"
  • 现在这很有趣。一旦我删除了对 Marshal.ReleaseComObject 的调用,它就彻底崩溃了!甚至无需等待垃圾回收。
  • 也许存在某种可重用性池。我可以清除或踢出 COM 对象吗?
  • 没有可重用的 COM 对象池。您可以使用GCHandle.Alloc 防止COM 对象被GC,但是,这是错误的。我认为这个问题是通过以下方式引入的:“COM 对象最近具有 MTA 功能......当它们只是 STA 时,没有这样的问题”。这些对象是用ThreadingModel="Free" 还是ThreadingModel="Both" 注册的?您确定他们在内部不使用任何其他或第 3 方 COM 对象,可能仍然是 STA?
  • 谢谢。请详细说明 GCHandle.Alloc (作为一个极端的解决方案)。是的,当然问题是在他们转换为 MTA 时引入的。是的,它们使用 ThreadingModel=Both 注册,并且在 WCF 之外一切正常。

标签: wcf com garbage-collection access-violation clarion


【解决方案1】:

好的。看来我在上

这是该死的隐藏单例对象,或者更确切地说,是编写 COM 的平台的运行时库 (SoftVelocity Clarion)。当启动 COM 被杀死时,它由于某种原因被释放,可能是因为引用计数下降,是时候卸载 DLL 本身了。虽然当我调整DllCanUnloadNow 时,它并没有帮助,但我会弄清楚它来自哪里。

编辑:Clarion 对 COM 对象的支持并不简单。由模板生成的代码执行数据库字典(分别为DctInitDctKill)和主程序中的一些特定类的分配和释放,当主线程结束时结束。然而,在 MTA COM 对象中,主线程的结束并不意味着程序的结束。因此,最简单的解决方案是嵌入代码以防止执行DctKill

另外,不要忘记在 .Destruct 方法中调用 AttachThreadToClarion(TRUE),因为垃圾回收线程会有所不同。

此问题可能会在广泛使用运行时或全局对象的老一代 IDE 中出现。谨防。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    相关资源
    最近更新 更多