我有一个C#COM DLL,它使用System.Management
命名空间调用WMI。 DLL正在加载到C ++服务中。每当我调用WMI类时,我都会看到巨大的内存泄漏。大约一个小时后,我使用了超过1 GB的内存。
如果我使用相同的COM DLL并使用Reflection.LoadFrom
将其加载到PowerShell中,它不会泄漏内存。我已经像这样修改了DLL并且它不再泄漏(仍然使用COM加载到服务中):
public class MyComObject
{
public void CallCom()
{
CallSomeWMIStuff();
}
}
对此。这不再泄漏!
public class MyComObject
{
public void CallCom()
{
//CallSomeWMIStuff();
}
}
以下是一些WMI代码的示例:
var scope = new ManagementScope( "root\\cimv2" );
scope.Connect();
using (var myservice = GetService("SomeService", scope))
{
//Some Stuff
}
...
ManagementObject GetService(string serviceName, MangementScope scope)
{
ManagementPath wmiPath = new ManagementPath( serviceName );
using (ManagementClass serviceClass = new ManagementClass( scope, wmiPath, null ))
{
using (ManagementObjectCollection services = serviceClass.GetInstances())
{
ManagementObject serviceObject = null;
// If this service class does not have an instance, create one.
if (services.Count == 0)
{
serviceObject = serviceClass.CreateInstance();
}
else
{
foreach (ManagementObject service in services)
{
serviceObject = service;
break;
}
}
return serviceObject;
}
}
}
编辑:C ++片段:
NAMESPACE::ICSharpComPtr pCSharpCom = NULL;
HRESULT hr = pCSharpCom .CreateInstance(NAMESPACE::CLSID_CSharpCom);
if (FAILED(hr))
{
Log("Failed (hr=%08x)", hr);
return hr;
}
try
{
_bstr_t bstrData = pCSharpCom ->GetData();
strLine = (LPCTSTR)bstrData;
strMessage += strLine;
}
catch (_com_error& err)
{
_bstr_t desc = GetErrorMessage(err);
Log("Excepton %S", (const wchar_t*)desc);
return 0;
}
pCSharpCom ->Release();
有没有人见过这样的东西?我们看到C ++ \ CLI的类似问题是直接加载不同的WMI相关DLL。
最终,WMI服务将不再响应,我也必须重新启动该服务。
编辑:
这与COM对象的单元状态有关。添加了CoInitializeEx
而不是CoInitialize
。我将线程设置为MTA。起初它看起来并没有起作用,直到我意识到第一次调用该方法时,我们看到线程状态设置为STA而不是MTA!随后的每个电话都是MTA。如果我立即返回,在线程为STA时调用System.Management
类之前,我将不再泄漏内存!
知道为什么第一个是STA?
答案 0 :(得分:1)
RCW实现中没有处置,因此您可以使用GC来释放默认情况下创建的com对象。但是,完成COM对象后,可以尝试在RCW实例上使用Marshal.FinalReleaseComObject。将强制包装的COM对象上的引用计数为零,它应该释放。但是,这也使得RCW实例无用,所以在你调用它时要小心。
答案 1 :(得分:0)
问题与创建COM对象的线程的单元状态有关。有一个线程将COM对象创建为MTA,另一个线程将COM对象创建为STA。首先创建STA线程,然后导致MTA线程出现问题。这导致终结器在GetToSTA上阻塞。