我在使用PDH库的时候遇到一个内存泄漏的问题(I encountered a memory leak issue while using the PDH library)

梓豪 丁 0 信誉分
2024-09-09T07:43:00.7966667+00:00

我使用PDH库实现获取cpu、内存和硬盘的情况,按照文档上提供的示例编写好的我的代码,最后测试通过了,成功获取了信息。但是我发现当我调用一个PdhAddCounterW函数的时候,我的程序的内存占用多了5MB左右,且在最后成功调用PdhCloseQuery之后,这部分内存并没有得到释放,多次测试都是这种情况。当我屏蔽掉调用pdh库的这部分代码时,就没有这种情况了。

pdh.h所在目录:C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include

我的系统版本:Windows 10 专业版 22H2

I used the PDH library to obtain information about CPU, memory, and hard drive. I wrote my code according to the examples provided in the documentation, and finally passed the test, successfully obtaining the information. But I found that when I called a PdhAddCounterW function, my program's memory usage increased by about 5MB, and after successfully calling PdhCloseQuery, this part of memory was not released. This has been the case in multiple tests. When I blocked the part of the code that calls the PDH library, this situation no longer exists.

pdh. h directory: C: \ Program Files \ Microsoft SDKs \ Windows \ v6.0A \ Include

My system version: Windows 10 Professional 22H2

std::string GetHardwareRealTimeInfo()
{
    std::stringstream ss;
    PDH_HQUERY query;
    PDH_HCOUNTER cpuCounter, memCounter, diskReadCounter, diskWriteCounter, diskTransfersCounter;
    PDH_FMT_COUNTERVALUE counterValue;
    DWORD error;

    do 
    {
        // Initialize PDH
        error = PdhOpenQuery(NULL, 0, &query);
        if (error != ERROR_SUCCESS) {
            return "";
        }

        error = PdhAddCounterW(query, L"\\Processor(_Total)\\% Processor Time", 0, &cpuCounter);
        error = PdhAddCounterW(query, L"\\Memory\\Available MBytes", 0, &memCounter);
        error = PdhAddCounterW(query, L"\\PhysicalDisk(_Total)\\Avg. Disk sec/Read", 0, &diskReadCounter);
        error = PdhAddCounterW(query, L"\\PhysicalDisk(_Total)\\Avg. Disk sec/Write", 0, &diskWriteCounter);
        error = PdhAddCounterW(query, L"\\PhysicalDisk(_Total)\\Disk Bytes/sec", 0, &diskTransfersCounter);

        if (error != ERROR_SUCCESS) {
            break;
        }

        // Collect data
        error = PdhCollectQueryData(query);
        if (error != ERROR_SUCCESS) {
            break;
        }

        // Sleep to allow counters to update
        Sleep(1000);

        // Collect data again
        error = PdhCollectQueryData(query);
        if (error != ERROR_SUCCESS) {
            break;
        }
        
        ss << std::endl;

        // Get CPU speed
        error = PdhGetFormattedCounterValue(cpuCounter, PDH_FMT_DOUBLE, NULL, &counterValue);
        if (error != ERROR_SUCCESS) {
            break;
        } else {
            ss << "\tCPU Utilization: " << std::fixed << std::setprecision(1) << counterValue.doubleValue << "%" << std::endl;
        }

        // Get Memory usage
        error = PdhGetFormattedCounterValue(memCounter, PDH_FMT_DOUBLE, NULL, &counterValue);
        if (error != ERROR_SUCCESS) {
            break;
        } else {
            MEMORYSTATUSEX statex;
            statex.dwLength = sizeof(statex);
            if (GlobalMemoryStatusEx(&statex)) {
                double totalMemoryMB = static_cast<double>(statex.ullTotalPhys) / (1024 * 1024);
                double availableMemoryMB = counterValue.doubleValue;

                // Calculate memory usage percentage
                double usedMemoryMB = totalMemoryMB - availableMemoryMB;
                ss << "\tAvailable Memory: " << std::fixed << std::setprecision(1)
                    << usedMemoryMB / 1024.0
                    << "/" << totalMemoryMB / 1024.0 << "GB ("
                    << (usedMemoryMB / totalMemoryMB) * 100.0 
                    << "%)" << std::endl;;
            } else {
                break;
            }

        }

        // Get Disk I/O
        error = PdhGetFormattedCounterValue(diskReadCounter, PDH_FMT_DOUBLE, NULL, &counterValue);
        if (error != ERROR_SUCCESS) {
            break;
        } else {
            ss << "\tDisk Read (ms): " << counterValue.doubleValue * 1000.0 << std::endl;
        }

        error = PdhGetFormattedCounterValue(diskWriteCounter, PDH_FMT_DOUBLE, NULL, &counterValue);
        if (error != ERROR_SUCCESS) {
            break;
        } else {
            ss << "\tDisk Write (ms): " << counterValue.doubleValue * 1000.0 << std::endl;
        }

        error = PdhGetFormattedCounterValue(diskTransfersCounter, PDH_FMT_DOUBLE, NULL, &counterValue);
        if (error != ERROR_SUCCESS) {
            break;
        } else {
            ss << "\tDisk Transfers (MB/s): " << std::fixed << std::setprecision(1) << counterValue.doubleValue / 1024.0 / 1024.0 << std::endl;
        }

    } while(false);
    error = PdhCloseQuery(query);
    if (error != ERROR_SUCCESS) {
        error = ERROR_SUCCESS;
    }
    return ss.str();
}

Windows API - Win32
Windows API - Win32
一组适用于桌面和服务器应用程序的核心 Windows 应用程序编程接口 (API)。 以前称为 Win32 API。
98 个问题
{count} 票

1 个答案

排序依据: 非常有帮助
  1. Tong Xu - MSFT 2,456 信誉分 Microsoft 供应商
    2024-09-09T09:15:05.45+00:00

    你好!@梓豪 丁

    请在每个失败条件的处理语句中添加 PdhRemoveCounter与PdhCloseQuery。比如:

     status = PdhGetFormattedCounterValue(cntProcessMemory, PDH_FMT_DOUBLE, &dwValue, &pdhValue);
       if (ERROR_SUCCESS != status)
       {
           MessageBox(NULL, TEXT("得到数据失败"), TEXT(""), MB_OK);
           PdhRemoveCounter(cntProcessMemory);
           PdhCloseQuery(query);
           return -1;
       }
    

    浏览性能计数器中每个失败都返回至Cleanup,我在我的测试程序加入后Process Memory都处于稳定,无论数据获取成功与否。

    0 个注释 无注释

你的答案

问题作者可以将答案标记为“接受的答案”,这有助于用户了解已解决作者问题的答案。