У меня есть 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?