C++ 如何从32位进程获取64位进程的可靠内存使用信息?
我的目标是获取任意进程的内存使用信息。我通过32位进程执行以下操作:C++ 如何从32位进程获取64位进程的可靠内存使用信息?,c++,winapi,memory,windows-applications,wow64,C++,Winapi,Memory,Windows Applications,Wow64,我的目标是获取任意进程的内存使用信息。我通过32位进程执行以下操作: HANDLE hProc = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, 0, pid); if(hProc) { PROCESS_MEMORY_COUNTERS_EX pmx = {0}; if(::GetProcessMemoryInfo(hProc, (PROCESS_MEMORY_COUNTERS*)&pm
HANDLE hProc = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, 0, pid);
if(hProc)
{
PROCESS_MEMORY_COUNTERS_EX pmx = {0};
if(::GetProcessMemoryInfo(hProc, (PROCESS_MEMORY_COUNTERS*)&pmx, sizeof(pmx)))
{
wprintf(L"Working set: %.02f MB\n", pmx.WorkingSetSize / (1024.0 * 1024.0));
wprintf(L"Private bytes: %.02f MB\n", pmx.PrivateUsage / (1024.0 * 1024.0));
}
::CloseHandle(hProc);
}
问题是,如果pid
进程是一个64位进程,它可能分配了超过4GB的内存,这将使pmx.WorkingSetSize
和pmx.privateausage
都溢出,这两个都是32位进程中的32位变量。因此,在这种情况下,不是失败,而是两个指标都返回为UINT\u MAX
——这是错误的
所以我想知道,如果有可靠的API从32位应用程序中的任意进程检索内存使用情况?为什么不将此应用程序编译为64位,然后您应该能够收集32位和64位进程的内存使用情况。为什么不将此应用程序编译为64位,然后您应该能够收集内存使用情况32位和64位进程的内存使用情况。WMI Win32\u进程提供程序有许多64位内存号。不确定您要查找的所有内容是否都存在。WMI Win32\u进程提供程序有许多64位内存号。不确定您所追求的一切是否都存在。有一个可靠的API称为“” Windows的stock
perfmon
实用程序是Windows性能计数器应用程序的经典示例。Process Explorer还使用它来收集流程统计信息
它的优点是,您甚至不需要SeDebugPrivilege
来获得对其他进程的PROCESS\u VM\u READ
访问权。请注意,访问权限仅限于属于性能监视用户组的用户 PDH背后的理念是:
- 查询对象
- 一个或多个计数器
- 根据要求或定期创建样本
- 获取您要求的数据
GetProcessMemoryInfo()
。
当然,有足够的空间来调整以下代码或根据您的需要进行调整。我还见过一些人创建了更通用的C++包装器。
宣言
#包括
#包括
#包括
#包括
#包括
#pragma注释(lib,“Pdh.lib”)
类进程\内存\信息
{
私人:
使用pd_t=std::tuple;//性能数据类型
静态constexpr size\u t pidIdx=0;
静态constexpr size\u t wsIdx=1;
静态constexpr size\u t pbIdx=2;
无结构的
{
布尔运算符()(常数局部和左、常数局部和右)常数
{
返回std::get(左)
实施
#包括
#包括
#包括
#包括
使用std::unique\u ptr;
使用std::pair;
使用std::数组;
使用std::使_唯一;
使用std::get;
进程内存信息::~进程内存信息()
{
PdhCloseQuery(pdhQuery);
}
bool进程\内存\信息::设置\查询()
{
如果(pdhQuery)
返回true;
if(PdhOpenQuery(nullptr、0和pdhQuery)
返回false;
尺寸i=0;
for(自动和反向路径:数组{{
{nullptr,L“进程”,L“*”,nullptr,0,L“ID进程”},
{nullptr,L“进程”,L“*”,nullptr,0,L“工作集”},
{nullptr,L“进程”,L“*”,nullptr,0,L“私有字节”}
}})
{
wchar_t pathStr[PDH_MAX_COUNTER_PATH]={};
德沃德尺寸;
PdhMakeCounterPath(&counterPath,pathStr,&(size=_countof(pathStr)),0);
PdhAddEnglishCounter(pdhQuery、pathStr、0和pdhCounters[ui++]);
}
返回true;
}
bool进程\内存\信息::获取样本()
{
if(PdhCollectQueryData(pdhQuery)
返回false;
德沃德·尼特姆=0;
德沃德尺寸;
PdhGetFormattedCounterArray(pdhCounters[0],PDH\u FMT\u LONG,&(size=0),&nItems,nullptr);
自动值buf=使_唯一(大小);
PdhGetFormattedCounterArray(pdhCounters_u[0],PDH_FMT_LONG,和size,和nItems,PPDH_FMT_COUNTERVALUE_项(valuesBuf.get());
唯一的ptr pidValues{PPDH_FMT_COUNTERVALUE_项(valuesBuf.release())};
valuesBuf=使_唯一(大小);
PdhGetFormattedCounterArray(pdhCounters_u[1],PDH_FMT_LARGE,size,nItems,PPDH_FMT_COUNTERVALUE_项(valuesBuf.get());
唯一的\u ptr wsValues{PPDH\u FMT\u COUNTERVALUE\u项(valuesBuf.release())};
valuesBuf=使_唯一(大小);
PdhGetFormattedCounterArray(pdhCounters_u[2],PDH_FMT_LARGE,size,nItems,PPDH_FMT_COUNTERVALUE_项(valuesBuf.get());
唯一的\u ptr pbValues{PPDH\u FMT\u COUNTERVALUE\u项(valuesBuf.release())};
perfData_uu.clear();
性能数据储备(nItems);
对于(大小i=0,n=nItems;i#include <tuple>
#include <array>
#include <vector>
#include <stdint.h>
#include <Pdh.h>
#pragma comment(lib, "Pdh.lib")
class process_memory_info
{
private:
using pd_t = std::tuple<DWORD, ULONGLONG, ULONGLONG>; // performance data type
static constexpr size_t pidIdx = 0;
static constexpr size_t wsIdx = 1;
static constexpr size_t pbIdx = 2;
struct less_pd
{
bool operator ()(const pd_t& left, const pd_t& right) const
{
return std::get<pidIdx>(left) < std::get<pidIdx>(right);
}
};
public:
~process_memory_info();
bool setup_query();
bool take_sample();
std::pair<uintmax_t, uintmax_t> get_memory_info(DWORD pid) const;
private:
PDH_HQUERY pdhQuery_ = nullptr;
std::array<PDH_HCOUNTER, std::tuple_size_v<pd_t>> pdhCounters_ = {};
std::vector<pd_t> perfData_;
};
#include <memory>
#include <execution>
#include <algorithm>
#include <stdlib.h>
using std::unique_ptr;
using std::pair;
using std::array;
using std::make_unique;
using std::get;
process_memory_info::~process_memory_info()
{
PdhCloseQuery(pdhQuery_);
}
bool process_memory_info::setup_query()
{
if (pdhQuery_)
return true;
if (PdhOpenQuery(nullptr, 0, &pdhQuery_))
return false;
size_t i = 0;
for (auto& counterPath : array<PDH_COUNTER_PATH_ELEMENTS, std::tuple_size_v<pd_t>>{ {
{ nullptr, L"Process", L"*", nullptr, 0, L"ID Process" },
{ nullptr, L"Process", L"*", nullptr, 0, L"Working Set" },
{ nullptr, L"Process", L"*", nullptr, 0, L"Private Bytes" }
}})
{
wchar_t pathStr[PDH_MAX_COUNTER_PATH] = {};
DWORD size;
PdhMakeCounterPath(&counterPath, pathStr, &(size = _countof(pathStr)), 0);
PdhAddEnglishCounter(pdhQuery_, pathStr, 0, &pdhCounters_[i++]);
}
return true;
}
bool process_memory_info::take_sample()
{
if (PdhCollectQueryData(pdhQuery_))
return false;
DWORD nItems = 0;
DWORD size;
PdhGetFormattedCounterArray(pdhCounters_[0], PDH_FMT_LONG, &(size = 0), &nItems, nullptr);
auto valuesBuf = make_unique<BYTE[]>(size);
PdhGetFormattedCounterArray(pdhCounters_[0], PDH_FMT_LONG, &size, &nItems, PPDH_FMT_COUNTERVALUE_ITEM(valuesBuf.get()));
unique_ptr<PDH_FMT_COUNTERVALUE_ITEM[]> pidValues{ PPDH_FMT_COUNTERVALUE_ITEM(valuesBuf.release()) };
valuesBuf = make_unique<BYTE[]>(size);
PdhGetFormattedCounterArray(pdhCounters_[1], PDH_FMT_LARGE, &size, &nItems, PPDH_FMT_COUNTERVALUE_ITEM(valuesBuf.get()));
unique_ptr<PDH_FMT_COUNTERVALUE_ITEM[]> wsValues{ PPDH_FMT_COUNTERVALUE_ITEM(valuesBuf.release()) };
valuesBuf = make_unique<BYTE[]>(size);
PdhGetFormattedCounterArray(pdhCounters_[2], PDH_FMT_LARGE, &size, &nItems, PPDH_FMT_COUNTERVALUE_ITEM(valuesBuf.get()));
unique_ptr<PDH_FMT_COUNTERVALUE_ITEM[]> pbValues{ PPDH_FMT_COUNTERVALUE_ITEM(valuesBuf.release()) };
perfData_.clear();
perfData_.reserve(nItems);
for (size_t i = 0, n = nItems; i < n; ++i)
{
perfData_.emplace_back(pidValues[i].FmtValue.longValue, wsValues[i].FmtValue.largeValue, pbValues[i].FmtValue.largeValue);
}
std::sort(std::execution::par_unseq, perfData_.begin(), perfData_.end(), less_pd{});
return true;
}
pair<uintmax_t, uintmax_t> process_memory_info::get_memory_info(DWORD pid) const
{
auto it = std::lower_bound(perfData_.cbegin(), perfData_.cend(), pd_t{ pid, 0, 0 }, less_pd{});
if (it != perfData_.cend() && get<pidIdx>(*it) == pid)
return { get<wsIdx>(*it), get<pbIdx>(*it) };
else
return {};
}
int main()
{
process_memory_info pmi;
pmi.setup_query();
DWORD pid = 4;
pmi.take_sample();
auto[workingSet, privateBytes] = pmi.get_memory_info(pid);
return 0;
}