在加载时调用COM对象时COM +挂起

时间:2011-06-16 14:41:59

标签: com vb6 com+

我们有一些COM +代码用每个人最喜欢的语言编写(?) - VB6。此COM +组件调用由第三方编写的标准COM组件,该组件执行对SQL Server数据库的调用。我们在COM +中没有做任何花哨的事 - 只不过(这只是一个例子;我们并没有真正调用我们的函数doStuff :-)):

Function doStuff
   Dim o As Library.Object
   Set o = New Library.Object
   str = o.DoSomething()
   Set o = Nothing
   doStuff = str
End Function

作为一个可怕的快速压力测试,我们将调用包装在一个简单的简单VBScript中,简单地创建对象,在循环中调用方法,将对象设置为空,并重复几次。然后,我们在命令提示符下同时运行其中的四个。

我们经历的是四个COM +窗口停止死亡,好像它们以某种方式相互阻挡。根据输出的行为,看起来不同的窗口在沿途的某处共享对象的实例:例如,窗口之间的输出出现的速度在窗口之间同步...所以两个可以在速度上起泡,而另外两个吐出一条线(当他们吐出线时,他们同时这样做)。

然后最终,所有四个窗口似乎都停止了 - 在组件服务中,我们看到呼叫时间开始爬升(因此从每次呼叫的几毫秒,它爬升到30,40秒)。有时dllhost.exe失败,我们会出现一个COM Surrogate错误对话框(此时窗口会在生成新的dllhost时恢复)。

数据库上有 no 活动,因此我们排除了数据库层阻塞的问题。通过将COM +组件设置为“Transactions:disabled”,我们似乎已经取得了更好的效果,但是挂起并没有消失。而不是new,我们将尝试使用CreateObject创建COM对象,以查看它的作用(如果有的话)。在COM +和VBScript层完成后,对象都设置为Nothing。

值得注意的是,如果直接从VBScript调用第三方库(绕过COM +),则不会出现问题。因此,似乎它与COM +与COM对象交互的方式有关,但除了摆弄组件服务中对象属性下的不同设置之外,还不确定其他事情是什么。

有什么建议可以引起这种情况吗?还是要调整设置?

额外信息
回答答案中的问题:

进一步的工作...... 看起来它是COM +或COM深处的同步问题。在我们的测试脚本中,如果我们在每次迭代时添加10-50ms的随机延迟,问题就会消失。如果我们有固定的延迟,我们会锁定。一些谷歌搜索似乎表明,对于负载很重的COM +,它可能是一个问题,即documented here on an MS blog。回到Server 2000机箱或Server 2003 SP1机箱会很高兴:这可能是接下来要看的......

3 个答案:

答案 0 :(得分:2)

听起来你可能会在公寓电话中遇到COM +和STA的问题。

微软曾经发过一篇由Michael McKeown发表的伟大文章,名为“从MTS移植到COM +时保持应用程序性能”,讨论了这个问题,但它看起来已被删除(有一个存档版本here)。

基本上,COM + STA线程池最多绑定5个活动到每个STA线程。当您进行公寓呼叫(第三方组件或SQL Server)时,COM +允许其他请求作为STA线程上的另一个活动进行服务。最多5个活动(每个线程)可能会发生这种情况。此外,一旦对另一个活动进行了控制,原始活动就无法重新获得控制,直到第二个活动完成。在负载很重和/或如果调用“长时间运行”,则第一个活动完成的时间是完成所有其他活动(在线程上)的时间总和。这可能会影响你的表现。

如果您能够切换整个COM +服务器的设置,则可以将COM +配置为使用旧的MTS 100 STA线程方法。有关详细信息,请参阅Registry key for tuning COM+ thread and activity。你可以看看这是否有助于你的表现。另一种方法是避免STA组件。

答案 1 :(得分:0)

或许COM+ Object Pooling Concepts以及Configuring a Component to Be Pooled等相关文章会有所帮助。

  

Poolable对象必须满足某些要求才能使多个客户端使用单个对象实例。例如,它们不能保持客户端状态或具有任何线程关联。

答案 2 :(得分:0)

我想到了两件事:

  1. 您是否尝试将o变量设为本地而非模块级别?

    功能doStuff    Dim o as Library.Object
       设置o = New Library.Object    str = o.DoSomething()    设置o = Nothing    doStuff = str 结束职能

  2. 您是否认为Library.Object组件和.DoSomething方法不包含全局变量(或MessageBox语句)?

  3. 你能在每一行之后抛出日志语句,看看代码窒息的地方吗?

  4. 点击ProcMon查看它何时停止访问注册表。最后一次通话失败了吗?如果是这样,去哪里?