返回「计算机、信息技术与工程」

Windows C++ 获取进程内存使用情况

更多
Markdown 结构化数据
本文目录 4 个章节

Windows C++ 获取进程内存使用情况

创建时间:2020/5/14 22:18

Windows 可通过 PSAPI 的 GetProcessMemoryInfo 读取进程内存计数器。常用字段包括:

  • WorkingSetSize:当前驻留在物理内存中的工作集;其中可能包含共享页面。
  • PeakWorkingSetSize:进程生命周期内的工作集峰值。
  • PrivateUsagePROCESS_MEMORY_COUNTERS_EX 提供的私有提交量,更接近该进程独自承担的已提交内存,但仍不等同于所有分析工具中的 “private working set”。
  • PageFaultCount:累计缺页次数,不能单独代表性能问题。

不同工具的“内存占用”可能采用工作集、私有工作集、提交量或 PSS 等不同口径,比较前必须确认定义。

查询当前进程

#include <windows.h>
#include <psapi.h>

#include <cstddef>
#include <iostream>

#pragma comment(lib, "psapi.lib")

int main() {
    PROCESS_MEMORY_COUNTERS_EX counters{};
    counters.cb = sizeof(counters);

    const BOOL ok = GetProcessMemoryInfo(
        GetCurrentProcess(),
        reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&counters),
        sizeof(counters));

    if (!ok) {
        std::cerr << "GetProcessMemoryInfo failed, error="
                  << GetLastError() << '\n';
        return 1;
    }

    constexpr std::size_t MiB = 1024 * 1024;
    std::cout << "Working set: "
              << counters.WorkingSetSize / MiB << " MiB\n";
    std::cout << "Peak working set: "
              << counters.PeakWorkingSetSize / MiB << " MiB\n";
    std::cout << "Private commit: "
              << counters.PrivateUsage / MiB << " MiB\n";
}

查询指定 PID

打开其他进程时只申请查询所需的最小权限,并检查句柄与 API 返回值:

#include <windows.h>
#include <psapi.h>

#include <iostream>

#pragma comment(lib, "psapi.lib")

bool PrintProcessMemory(DWORD processId) {
    HANDLE process = OpenProcess(
        PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,
        FALSE,
        processId);

    if (process == nullptr) {
        std::cerr << "OpenProcess failed, error=" << GetLastError() << '\n';
        return false;
    }

    PROCESS_MEMORY_COUNTERS_EX counters{};
    counters.cb = sizeof(counters);
    const BOOL ok = GetProcessMemoryInfo(
        process,
        reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&counters),
        sizeof(counters));

    if (ok) {
        std::cout << "PID " << processId
                  << ", working set=" << counters.WorkingSetSize
                  << " bytes, private commit=" << counters.PrivateUsage
                  << " bytes\n";
    } else {
        std::cerr << "GetProcessMemoryInfo failed, error="
                  << GetLastError() << '\n';
    }

    CloseHandle(process);
    return ok == TRUE;
}

某些受保护进程无法读取,提升到 SeDebugPrivilege 也不是通用解决方案。工具应正常处理访问被拒绝,并避免默认以管理员身份运行。

分析建议

  1. 固定构建、场景和采样时间,重复采样而非只看单点。
  2. 同时记录工作集、私有提交量和系统整体内存压力。
  3. 排查泄漏时结合堆快照、分配调用栈和对象生命周期。
  4. 64 位大小使用 SIZE_T/std::size_t,避免用 %d 截断。
  5. 句柄必须关闭;动态数组应使用标准容器或 RAII,避免手工 new[]/delete[] 错配。

参考资料