【发布时间】:2017-04-08 20:19:11
【问题描述】:
我在更改语言时遇到了一些WMI 内存泄漏问题。我已经在Task Manager 中检查过了。例如,我的应用程序占用 25 MB RAM,当更改语言时它会增长到 30 MB 和 35、40...并且永远不会释放它。
//Initialization
IWbemLocator *pLocator = 0;
IWbemServices *pService = 0;
IEnumWbemClassObject* pEnumerator = NULL;
IWbemClassObject *pclsObj = NULL;
while (pEnumerator)
{
hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
VARIANT processName;
pclsObj->Get(L"Name", 0, &processName, 0, 0);
QString userProcessName;
userProcessName = QString::fromWCharArray(processName.bstrVal);
emit testData(userProcessName);
VariantClear(&processName);
}
//Cleanup
pService->Release();
pLocator->Release();
//pEnumerator->Release(); - Clang Static Analyzer displays issue - called C++ object pointer is null
//pclsObj->Release(); - Clang Static Analyzer displays issue - called C++ object pointer is null
如何解决这个问题?提前致谢。
我检查过内存泄漏的测试截图:
代码:
int Test::allServicesWMIData()
{
HRESULT hres;
// Initialize COM.
hres = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
if (FAILED(hres))
{
emit initComLibError(QString(QObject::tr("Failed to initialize COM library. Error code =") + " 0x%1").arg(hexErrorData(hres)));
return 1; // Program has failed.
}
IWbemLocator *pLocator = 0;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *)&pLocator);
if (FAILED(hres))
{
emit errorCreateIWbemObject(QString(QObject::tr("Failed to create IWbemLocator object. Error code =") + " 0x%1").arg(hexErrorData(hres)));
CoUninitialize();
return 1; // Program has failed.
}
IWbemServices *pService = 0;
hres = pLocator->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
NULL, // User name
NULL, // User password
0, // Locale
NULL, // Security flags
0, // Authority
0, // Context object
&pService // IWbemServices proxy
);
if (FAILED(hres))
{
emit errorRootConnection(QString(QObject::tr("Could not connect. Error code =") + " 0x%1").arg(hexErrorData(hres)));
pLocator->Release();
CoUninitialize();
return 1; // Program has failed.
}
hres = CoSetProxyBlanket(
pService, // the proxy to set
RPC_C_AUTHN_WINNT, // authentication service
RPC_C_AUTHZ_NONE, // authorization service
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // authentication level
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
emit errorProxyBlanket(QString(QObject::tr("Could not set proxy blanket. Error code =") + " 0x%1").arg(hexErrorData(hres)));
pService->Release();
pLocator->Release();
CoUninitialize();
return 1; // Program has failed.
}
IEnumWbemClassObject* pEnumerator = NULL;
hres = pService->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_Service"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
IWbemClassObject *pclsObj = NULL;
if (FAILED(hres))
{
emit errorProcessQuery(QString(QObject::tr("Query for processes failed. Error code =") + " 0x%1").arg(hexErrorData(hres)));
pService->Release();
pLocator->Release();
CoUninitialize();
return 1; // Program has failed.
}
else
{
ULONG uReturn = 0;
while (pEnumerator)
{
hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
VARIANT serviceName;
VARIANT servicePath;
VARIANT serviceID;
VARIANT serviceType;
VARIANT serviceState;
VARIANT serviceStatus;
VARIANT serviceErrorControl;
VARIANT serviceStartMode;
VARIANT serviceWaitHint;
VARIANT serviceExitCode;
if (hres != 0) {
emit hardwareDataNotAvailable();
break;
} else {
pclsObj->Get(L"Caption", 0, &serviceName, 0, 0);
pclsObj->Get(L"PathName", 0, &servicePath, 0, 0);
pclsObj->Get(L"ProcessId", 0, &serviceID, 0, 0);
pclsObj->Get(L"ServiceType", 0, &serviceType, 0, 0);
pclsObj->Get(L"State", 0, &serviceState, 0, 0);
pclsObj->Get(L"Status", 0, &serviceStatus, 0, 0);
pclsObj->Get(L"ErrorControl", 0, &serviceErrorControl, 0, 0);
pclsObj->Get(L"StartMode", 0, &serviceStartMode, 0, 0);
pclsObj->Get(L"WaitHint", 0, &serviceWaitHint, 0, 0);
pclsObj->Get(L"ExitCode", 0, &serviceExitCode, 0, 0);
}
QString userServiceName = QString::fromWCharArray(serviceName.bstrVal);
QString userServicePath = QString::fromWCharArray(servicePath.bstrVal);
QString userServiceID = QString::number(serviceID.uintVal);
QString userServiceType = QString::fromWCharArray(serviceType.bstrVal);
QString userServiceState = QString::fromWCharArray(serviceState.bstrVal);
QString userServiceStatus = QString::fromWCharArray(serviceStatus.bstrVal);
QString userServiceErrorControl = QString::fromWCharArray(serviceErrorControl.bstrVal);
QString userServiceStartMode = QString::fromWCharArray(serviceStartMode.bstrVal);
QString userServiceWaitHint = QString::number(serviceWaitHint.uintVal);
QString userServiceExitCode = QString::number(serviceExitCode.uintVal);
emit appAllServicesData(userServiceName, userServicePath, userServiceID, userServiceType, userServiceState, userServiceStatus, userServiceErrorControl,
userServiceStartMode, userServiceWaitHint, userServiceExitCode);
VariantClear(&serviceName);
VariantClear(&servicePath);
VariantClear(&serviceID);
VariantClear(&serviceType);
VariantClear(&serviceState);
VariantClear(&serviceStatus);
VariantClear(&serviceErrorControl);
VariantClear(&serviceStartMode);
VariantClear(&serviceWaitHint);
VariantClear(&serviceExitCode);
}
}
// Cleanup
pService->Release();
pLocator->Release();
//pEnumerator->Release(); - Clang Static Analyzer displays issue - called C++ object pointer is null
//pclsObj->Release(); - Clang Static Analyzer displays issue - called C++ object pointer is null
CoUninitialize();
emit finished();
return 0; // Program successfully completed.
}
【问题讨论】:
-
任务管理器中没有一列显示进程占用的 RAM 量。你真正在看什么价值?为什么你认为存在内存泄漏?确保你理解memory management。
-
如果您需要发布屏幕截图,请将其放在您的问题中。并使用受支持的图像主机。 fastpic.ru 不是受支持的图像主机。
-
我的应用程序占用了内存并且从不释放它,所以我应该认为这不是泄漏吗?
-
这可能是也可能不是泄漏,我们不知道。查看您发布的代码,内存泄漏可能是您最不担心的问题。如发布的那样,该代码立即使进程因访问冲突而崩溃。我建议发布真实代码。
-
那个"minimal"怎么样?此外,既然你标记了这个问题c++,你为什么不使用智能指针?这将节省您实现手动资源管理的代码的三分之一。我不知道,为什么你也评论了
pEnumerator->Release();。这是记录在案的资源泄漏(请参阅IWbemServices::ExecQuery)。另外,您似乎对 COM 的理解不够深入,无法完成此操作(例如,您的VARIANTs 都没有被初始化)。
标签: c++ qt memory-leaks windows-applications