c#windows服务中vb6 COM dll使用的可用内存

时间:2013-09-06 07:52:42

标签: c#-4.0 service vb6

我遇到了一个使用解决方案中引用的VB6 COM dll的Windows服务的问题。

该服务是执行任务的调度程序。每个任务都在一个线程中执行,因此它允许用户同时执行某些任务。

当一个线程启动时,在c#中使用“New”语法创建一个对象(在名为C_AUTO的vb6 dll中)。此对象的构造函数创建其他对象以执行任务。任务完成后,C_AUTO的析构函数会使用set ... = nothing来销毁所有其他对象。对象C_AUTO被破坏,线程也被破坏。

我的问题是当服务执行另一个任务时,另一个线程被创建另一个C_AUTO对象。我添加了一个片段,在文件中写入内存指针的值,值相同,因此C_AUTO创建的所有对象都不会被销毁。

是否有另一种方法可以在没有“新”语法的情况下加载VB6 dll,这允许我在任务完成时卸载所有对象?因为在几天之后,该服务消耗了大量内存并且任务崩溃了。

感谢您的帮助

1 个答案:

答案 0 :(得分:7)

有一些关于VB6对象的令人不快的实现细节使得它们难以在C#服务中正确使用。 VB6对象是公寓线程的COM对象。这是一个昂贵的词,意味着它们不是线程安全的,COM确保它们以线程安全的方式使用。

C#服务几乎总是创建不适合公寓线程对象的线程。 COM将创建一个 new 线程,为这样的对象提供一个安全的家。这是昂贵的,一个新线程需要一兆字节的虚拟内存。

此外,只有在垃圾收集器运行时才会卸载这个对象(并且线程只会停止运行)。如果在VB6对象上进行大量调用但是自己没有分配很多.NET对象,则很容易遇到问题。这使得GC停止运行的频率足以让你在创建所有这些线程并吞下大量虚拟内存时遇到麻烦。当你创造了大约1800个,给予或接受时,你将获得OOM kaboom。

具体的解决方法是:

  • 使用Thread.SetApartmentState()方法在启动之前将线程切换到STA。这会阻止COM创建该辅助线程。请注意,使用Timer来运行服务等常用服务技术不合适,您必须在OnStart()方法中创建一个Thread。

  • 您可能必须调用Application.Run()来启动消息循环,这是STA线程的要求。这在服务中往往有点棘手,你从项目模板中得到的帮助很少,无法实现管道安装。你可以在没有抽水的情况下离开,但你必须确保在创建它的同一个线程上对VB6对象进行所有调用。出错的诊断方法是死锁。

  • 如果您确定GC运行频率不够(使用Perfmon.exe查看.NET计数器),那么您可能需要帮助并调用GC.Collect()来获取VB6对象已卸载。

在这里完成所有事情并不容易。如果您一直在考虑更新VB6代码,那么现在是个好时机。