ManagementObject在C#COM DLL中泄漏

时间:2011-11-17 15:36:44

标签: c# c++ com memory-leaks wmi

我有一个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?

2 个答案:

答案 0 :(得分:1)

RCW实现中没有处置,因此您可以使用GC来释放默认情况下创建的com对象。但是,完成COM对象后,可以尝试在RCW实例上使用Marshal.FinalReleaseComObject。将强制包装的COM对象上的引用计数为零,它应该释放。但是,这也使得RCW实例无用,所以在你调用它时要小心。

答案 1 :(得分:0)

问题与创建COM对象的线程的单元状态有关。有一个线程将COM对象创建为MTA,另一个线程将COM对象创建为STA。首先创建STA线程,然后导致MTA线程出现问题。这导致终结器在GetToSTA上阻塞。