调试一个VB6 COM+ Web应用程序挂起

4
我正在开发一个经典ASP Web应用程序,使用了几个VB6编写的老的COM组件。 所有的VB6组件都注册在一个COM+应用程序中,以自己的dllhost进程运行。 应用程序的大部分已转换为.Net,但仍有许多遗留页面和组件。 COM互操作在两个方向上被使用,从经典ASP和VB6调用一些.Net程序集,以及从ASP.Net调用VB6组件。 该应用程序在Windows Server 2008 R2(IIS 7.5)上运行于经典管道模式。
大部分情况下,该应用程序工作正常。 转向.Net的努力最终被放弃了,而是开发了新产品。 同时,必须维护旧产品状态。
我有问题跟踪一个间歇性的问题,即Web应用程序挂起。 用户只见到空白屏幕,而浏览器等待且服务器不响应。 悬挂持续到我手动杀死托管VB6组件的dllhost进程,因此我认为问题隐藏在组件中。 可能是内存泄漏或失控的循环。
系统每天有数千个用户,但问题只会在一两个星期发生一次。 幸运的是,我们有一个Web Farm,当服务器停止响应时,自动将服务器拉出,因此客户影响为零。 不过,我仍然想搞清楚发生了什么。
我重新编译了所有的VB6组件以包括调试符号并重新部署到生产环境。 当问题发生时,我使用32位任务管理器(c:\ windows\syswow64\taskmgr.exe)来获取dllhost进程的崩溃转储。 我最终得到一个dllhost.dmp文件,将其带到开发工作站并在VS2010中打开。 我在我的符号路径中有VB6创建的.pdb符号文件。 当我在VS2010中启动调试会话时,我可以转到模块屏幕,并查看确实加载了我组件的所有符号。
从这里开始怎么办呢? 调用堆栈没有显示任何我的组件。 它看起来像这样:
(图片已略)
顶部调用堆栈的反汇编看起来像这样:
(图片已略)
不确定我还能做什么。 我检查了调用堆栈每个框架的所有本地内容,对我来说都是无意义的。 我没有看到任何对我的组件的引用。
也许WinDbg会提供更多信息? 我不确定该从哪里开始。
我很确定,如果我能找到挂起发生时正在调用的VB6类/方法,我就能找到问题的根源。 我尝试添加了一些日志记录,结果不一致。
也许我的VB6组件完全没有问题,而是遇到了Windows或IIS中的某些错误?

任何建议都将受到赞赏,但目前放弃VB6不是一个选择。谢谢。


你是否使用了“无人值守执行”和“保留在内存中”的选项编译了你的VB6组件?在COM+下使用全局变量会导致很多问题,如果可能的话,请尝试转换为无状态类。 - wqw
是的,它们都已经打开了。除了常量之外,全局变量并不太多。我会看看能否将其分解出来。 - Matt Johnson-Pint
1个回答

1

这不是一个完整的答案,但是CoRegisterSurrogateEx文档记录了只要代理进程正在运行,它就会被阻塞:

CoRegisterSurrogateEx函数是一个阻塞函数。它在COM+确定进程将关闭之前不返回。在调用此函数之前,请将该线程上的COM初始化为多线程公寓(MTA)。

因此,我认为错误不在此调用堆栈上。(您可以看到它仍在等待WaitForSingleObject调用,很可能是它用于阻止进程关闭的机制)。


是的,我想它在等待我的代码中的某些东西,但是是什么呢?我该如何深入挖掘? - Matt Johnson-Pint
不,这里看到的线程正在监视(等待)托管进程的生命周期。实际的COM对象调用运行的线程必须是另一个线程。 - tcarvin
啊..我没意识到我只看到了单个线程的视图。经过一番挖掘,我现在知道如何获取所有线程的调用堆栈。该进程中有29个线程。 "并行堆栈"调试窗口显示了一个漂亮的树形结构,展示了哪些线程派生出其他线程。但我仍然没有在任何调用堆栈中看到我的代码。我应该寻找什么? - Matt Johnson-Pint
还有其他的dllhost进程吗? - Mark Bertenshaw
是的 - 我还有一个没注意到!它的内存占用要小得多。我想知道我怎么会有两个?我会再做一些转储。也许我会用这个得到更好的结果。 - Matt Johnson-Pint
我最终在垃圾堆里找到了一些VB代码,但似乎它不太可能是失败的关键点。这是一个简单的调用另一个VB函数,而该函数在应用程序中的许多其他地方都被使用而没有失败。我会继续深入挖掘。感谢你们目前为止提供的帮助。对于调试此类故障,还有其他建议吗? - Matt Johnson-Pint

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接