ManagementObject утечка в C # COM DLL - PullRequest
2 голосов
/ 17 ноября 2011

У меня есть C # COM DLL, которая вызывает WMI, используя пространство имен System.Management. DLL загружается в службу C ++. Каждый раз, когда я вызываю классы WMI, я вижу огромную утечку памяти. Примерно через час я использую более 1 ГБ памяти.

Если я возьму ту же COM DLL и загрузлю ее в PowerShell, используя Reflection.LoadFrom, она не утечет память. Я изменил 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, который напрямую загружает другую DLL, связанную с WMI.

В конце концов, служба WMI больше не будет отвечать на запросы, и мне придется также перезапустить эту службу.

Edit:

Это связано с состоянием квартиры объекта COM. Добавлен CoInitializeEx вместо CoInitialize. Я установил нить в MTA. Сначала это не выглядело так, как будто это работало, пока я не понял, что в первый раз, когда вызывался метод, мы видели состояние потока, установленное в STA, а не в MTA! Каждый последующий звонок будет MTA. Если бы я сразу же вернулся, прежде чем вызывать классы System.Management, когда поток был STA, я бы больше не терял память!

Есть идеи, почему первым будет STA?

Ответы [ 2 ]

1 голос
/ 17 ноября 2011

В реализации RCW нет распоряжения, поэтому вы можете использовать GC для освобождения созданных по умолчанию объектов com.Однако вы можете попробовать использовать Marshal.FinalReleaseComObject на экземпляре RCW, как только вы закончите с вашими COM-объектами.Это заставит ref ref обнуляться на обернутом COM-объекте, и он должен освободиться.Однако это также делает экземпляр RCW бесполезным, поэтому будьте осторожны, когда вы его называете.

0 голосов
/ 21 ноября 2011

Проблема была связана с состоянием квартиры потока, создающего COM-объект. Был один поток, который создал объект COM как MTA, и другой поток, который создавал объект COM как STA. Сначала был создан поток STA, а затем возникли проблемы с потоками MTA. Это привело к блокировке финализатора в GetToSTA.

...