如何测量 32 位程序中 64 位进程的内存使用情况?

Posted

技术标签:

【中文标题】如何测量 32 位程序中 64 位进程的内存使用情况?【英文标题】:How can I measure memory usage of 64-bit process in 32-bit program ? 【发布时间】:2017-01-23 10:36:38 【问题描述】:

我正在尝试从 C++ 中的 32 位进程测量 64 位应用程序的进程内存使用情况 (WorkingSetSize)。我尝试使用Toolhelp:

void GetProcMemoryInfo(const wchar_t * procName)

     PROCESSENTRY32 entry;
     entry.dwSize = sizeof(PROCESSENTRY32);

     HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

     if (Process32First(snapshot, &entry) == TRUE)
     
         while (Process32Next(snapshot, &entry) == TRUE)
         
             if (wcscmp(entry.szExeFile, procName) == 0)
             
                 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
                 PROCESS_MEMORY_COUNTERS objProcessMemoryInfo;

                 if (GetProcessMemoryInfo(hProcess, &objProcessMemoryInfo, sizeof(objProcessMemoryInfo)))
                 
                      wchar_t szProcessMemoryInfo[100];
                      wsprintf(szProcessMemoryInfo, L"Working Set Bytes (MB): %d\n", objProcessMemoryInfo.WorkingSetSize / (1024 * 1024));
                      OutputDebugString(szProcessMemoryInfo);
                 
                 CloseHandle(hProcess);
             
         
     
     CloseHandle(snapshot);

此解决方案工作正常,但前提是它构建为x64 应用程序。否则 - 我得到2^32 的最大值。我猜这种情况是PROCESS_MEMORY_COUNTERS 在内部使用SIZE_T。有没有其他方法可以测量进程内存使用情况,对它所构建的架构不敏感?

【问题讨论】:

从 64 位进程执行此操作,而不是从模拟器内部执行此操作 正如这里已经提到的:***.com/questions/15574638/…,结构中字段的大小由调用进程的位数定义,如果测量的进程是 x86-64 则可能发生溢出。所以使用 x86-64 进程进行测量。您可以编写一个“代理”应用程序,仅测量 x86-64 的内存使用情况,然后将值传递给原始 x86 进程(通过远程处理或任何其他 IPC)。 唉,有时候面对不切实际的限制,你只能放弃。 当然,WMI 使用外部 64 位进程完成它。在禁用 WMI 的机器上不起作用,这确实发生了。而且速度非常慢。但如果它符合您的要求,那就太好了。 嗯,它在某些机器上根本不起作用。如果可能,我希望避免使用 WMI 并使用 64 位进程。 Out of proc com 是一种方法,可以让您的主应用程序保持 32 位。工作集大小可能不是衡量内存使用情况的正确方法。 【参考方案1】:

我找到了答案,可以使用Windows Management Instrumentation

class WMI 

public:
     WMI();
    ~WMI();
     HRESULT Open(LPCTSTR machine=NULL, LPCTSTR user=NULL, LPCTSTR pass=NULL);
     void Close();
     HRESULT GetProcStringProperty(DWORD pid, TCHAR *name, TCHAR *value, DWORD len);
     int GetLastError();

private:
     IWbemServices *wbem;
     HRESULT result;
     BSTR GetProcQuery(DWORD pid);
;

使用以下函数检索属性的值:

HRESULT WMI::GetProcStringProperty(DWORD pid, TCHAR *name, TCHAR *value, DWORD len)

    IWbemClassObject *obj;
    VARIANT var;

    result = wbem->GetObject(GetProcQuery(pid), 0, 0, &obj, 0);

    if (FAILED(result)) 
        return result;
    

    result = obj->Get(name, 0, &var, 0, 0);

    if (SUCCEEDED(result)) 
        if (var.vt == VT_NULL) 
            result = E_INVALIDARG;
        
        else 
            lstrcpyn(value, var.bstrVal, len);
        
        VariantClear(&var);
    

    obj->Release();

    return result;

使用以下函数检索内存使用值:

int wmiGetMemProc(uint64_t pid, uint64_t *procmem)

    int status;
    TCHAR buf[MEM_MAX];
    WMI *wmi = new WMI();

    if (FAILED(wmi->Open())) 
        return wmi->GetLastError();
    

    if (FAILED(wmi->GetProcStringProperty(pid, L"WorkingSetSize", buf, MEM_MAX))) 
        status = wmi->GetLastError();
    
    else 
        *procmem = _wcstoui64(buf, NULL, 10);
    

    wmi->Close();
    delete wmi;

    return status;

它工作得很好。

【讨论】:

以上是关于如何测量 32 位程序中 64 位进程的内存使用情况?的主要内容,如果未能解决你的问题,请参考以下文章

在 64 位操作系统上,32 位进程可以访问多少内存?

如何在 64 位应用程序中使用 32 位指针?

boost::interprocess 32 位和 64 位进程之间的共享内存

VS2008的32位的程序如何移植到64位的系统,具体操作上的问题

如何从 32 位进程启动 64 位进程

如何使 .NET 可执行文件在 64 位操作系统上作为 32 位进程运行?